1   /*
2    * Copyright (c) 1997, 2010, Oracle and/or its affiliates. All rights reserved.
3    * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4    *
5    * This code is free software; you can redistribute it and/or modify it
6    * under the terms of the GNU General Public License version 2 only, as
7    * published by the Free Software Foundation.  Oracle designates this
8    * particular file as subject to the "Classpath" exception as provided
9    * by Oracle in the LICENSE file that accompanied this code.
10   *
11   * This code is distributed in the hope that it will be useful, but WITHOUT
12   * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13   * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
14   * version 2 for more details (a copy is included in the LICENSE file that
15   * accompanied this code).
16   *
17   * You should have received a copy of the GNU General Public License version
18   * 2 along with this work; if not, write to the Free Software Foundation,
19   * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
20   *
21   * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
22   * or visit www.oracle.com if you need additional information or have any
23   * questions.
24   */
25  
26  package javax.swing;
27  
28  import java.util.*;
29  
30  import java.applet.Applet;
31  import java.awt.*;
32  import java.awt.event.*;
33  import java.awt.print.*;
34  
35  import java.beans.*;
36  
37  import java.io.Serializable;
38  import java.io.ObjectOutputStream;
39  import java.io.ObjectInputStream;
40  import java.io.IOException;
41  
42  import javax.accessibility.*;
43  
44  import javax.swing.event.*;
45  import javax.swing.plaf.*;
46  import javax.swing.table.*;
47  import javax.swing.border.*;
48  
49  import java.text.NumberFormat;
50  import java.text.DateFormat;
51  import java.text.MessageFormat;
52  
53  import javax.print.attribute.*;
54  import javax.print.PrintService;
55  
56  import sun.swing.SwingUtilities2;
57  import sun.swing.SwingUtilities2.Section;
58  import static sun.swing.SwingUtilities2.Section.*;
59  import sun.swing.PrintingStatus;
60  import sun.swing.SwingLazyValue;
61  
62  /**
63   * The <code>JTable</code> is used to display and edit regular two-dimensional tables
64   * of cells.
65   * See <a href="http://java.sun.com/docs/books/tutorial/uiswing/components/table.html">How to Use Tables</a>
66   * in <em>The Java Tutorial</em>
67   * for task-oriented documentation and examples of using <code>JTable</code>.
68   *
69   * <p>
70   * The <code>JTable</code> has many
71   * facilities that make it possible to customize its rendering and editing
72   * but provides defaults for these features so that simple tables can be
73   * set up easily.  For example, to set up a table with 10 rows and 10
74   * columns of numbers:
75   * <p>
76   * <pre>
77   *      TableModel dataModel = new AbstractTableModel() {
78   *          public int getColumnCount() { return 10; }
79   *          public int getRowCount() { return 10;}
80   *          public Object getValueAt(int row, int col) { return new Integer(row*col); }
81   *      };
82   *      JTable table = new JTable(dataModel);
83   *      JScrollPane scrollpane = new JScrollPane(table);
84   * </pre>
85   * <p>
86   * {@code JTable}s are typically placed inside of a {@code JScrollPane}.  By
87   * default, a {@code JTable} will adjust its width such that
88   * a horizontal scrollbar is unnecessary.  To allow for a horizontal scrollbar,
89   * invoke {@link #setAutoResizeMode} with {@code AUTO_RESIZE_OFF}.
90   * Note that if you wish to use a <code>JTable</code> in a standalone
91   * view (outside of a <code>JScrollPane</code>) and want the header
92   * displayed, you can get it using {@link #getTableHeader} and
93   * display it separately.
94   * <p>
95   * To enable sorting and filtering of rows, use a
96   * {@code RowSorter}.
97   * You can set up a row sorter in either of two ways:
98   * <ul>
99   *   <li>Directly set the {@code RowSorter}. For example:
100  *        {@code table.setRowSorter(new TableRowSorter(model))}.
101  *   <li>Set the {@code autoCreateRowSorter}
102  *       property to {@code true}, so that the {@code JTable}
103  *       creates a {@code RowSorter} for
104  *       you. For example: {@code setAutoCreateRowSorter(true)}.
105  * </ul>
106  * <p>
107  * When designing applications that use the <code>JTable</code> it is worth paying
108  * close attention to the data structures that will represent the table's data.
109  * The <code>DefaultTableModel</code> is a model implementation that
110  * uses a <code>Vector</code> of <code>Vector</code>s of <code>Object</code>s to
111  * store the cell values. As well as copying the data from an
112  * application into the <code>DefaultTableModel</code>,
113  * it is also possible to wrap the data in the methods of the
114  * <code>TableModel</code> interface so that the data can be passed to the
115  * <code>JTable</code> directly, as in the example above. This often results
116  * in more efficient applications because the model is free to choose the
117  * internal representation that best suits the data.
118  * A good rule of thumb for deciding whether to use the <code>AbstractTableModel</code>
119  * or the <code>DefaultTableModel</code> is to use the <code>AbstractTableModel</code>
120  * as the base class for creating subclasses and the <code>DefaultTableModel</code>
121  * when subclassing is not required.
122  * <p>
123  * The "TableExample" directory in the demo area of the source distribution
124  * gives a number of complete examples of <code>JTable</code> usage,
125  * covering how the <code>JTable</code> can be used to provide an
126  * editable view of data taken from a database and how to modify
127  * the columns in the display to use specialized renderers and editors.
128  * <p>
129  * The <code>JTable</code> uses integers exclusively to refer to both the rows and the columns
130  * of the model that it displays. The <code>JTable</code> simply takes a tabular range of cells
131  * and uses <code>getValueAt(int, int)</code> to retrieve the
132  * values from the model during painting.  It is important to remember that
133  * the column and row indexes returned by various <code>JTable</code> methods
134  * are in terms of the <code>JTable</code> (the view) and are not
135  * necessarily the same indexes used by the model.
136  * <p>
137  * By default, columns may be rearranged in the <code>JTable</code> so that the
138  * view's columns appear in a different order to the columns in the model.
139  * This does not affect the implementation of the model at all: when the
140  * columns are reordered, the <code>JTable</code> maintains the new order of the columns
141  * internally and converts its column indices before querying the model.
142  * <p>
143  * So, when writing a <code>TableModel</code>, it is not necessary to listen for column
144  * reordering events as the model will be queried in its own coordinate
145  * system regardless of what is happening in the view.
146  * In the examples area there is a demonstration of a sorting algorithm making
147  * use of exactly this technique to interpose yet another coordinate system
148  * where the order of the rows is changed, rather than the order of the columns.
149  * <p>
150  * Similarly when using the sorting and filtering functionality
151  * provided by <code>RowSorter</code> the underlying
152  * <code>TableModel</code> does not need to know how to do sorting,
153  * rather <code>RowSorter</code> will handle it.  Coordinate
154  * conversions will be necessary when using the row based methods of
155  * <code>JTable</code> with the underlying <code>TableModel</code>.
156  * All of <code>JTable</code>s row based methods are in terms of the
157  * <code>RowSorter</code>, which is not necessarily the same as that
158  * of the underlying <code>TableModel</code>.  For example, the
159  * selection is always in terms of <code>JTable</code> so that when
160  * using <code>RowSorter</code> you will need to convert using
161  * <code>convertRowIndexToView</code> or
162  * <code>convertRowIndexToModel</code>.  The following shows how to
163  * convert coordinates from <code>JTable</code> to that of the
164  * underlying model:
165  * <pre>
166  *   int[] selection = table.getSelectedRows();
167  *   for (int i = 0; i &lt; selection.length; i++) {
168  *     selection[i] = table.convertRowIndexToModel(selection[i]);
169  *   }
170  *   // selection is now in terms of the underlying TableModel
171  * </pre>
172  * <p>
173  * By default if sorting is enabled <code>JTable</code> will persist the
174  * selection and variable row heights in terms of the model on
175  * sorting.  For example if row 0, in terms of the underlying model,
176  * is currently selected, after the sort row 0, in terms of the
177  * underlying model will be selected.  Visually the selection may
178  * change, but in terms of the underlying model it will remain the
179  * same.  The one exception to that is if the model index is no longer
180  * visible or was removed.  For example, if row 0 in terms of model
181  * was filtered out the selection will be empty after the sort.
182  * <p>
183  * J2SE 5 adds methods to <code>JTable</code> to provide convenient access to some
184  * common printing needs. Simple new {@link #print()} methods allow for quick
185  * and easy addition of printing support to your application. In addition, a new
186  * {@link #getPrintable} method is available for more advanced printing needs.
187  * <p>
188  * As for all <code>JComponent</code> classes, you can use
189  * {@link InputMap} and {@link ActionMap} to associate an
190  * {@link Action} object with a {@link KeyStroke} and execute the
191  * action under specified conditions.
192  * <p>
193  * <strong>Warning:</strong> Swing is not thread safe. For more
194  * information see <a
195  * href="package-summary.html#threading">Swing's Threading
196  * Policy</a>.
197  * <p>
198  * <strong>Warning:</strong>
199  * Serialized objects of this class will not be compatible with
200  * future Swing releases. The current serialization support is
201  * appropriate for short term storage or RMI between applications running
202  * the same version of Swing.  As of 1.4, support for long term storage
203  * of all JavaBeans<sup><font size="-2">TM</font></sup>
204  * has been added to the <code>java.beans</code> package.
205  * Please see {@link java.beans.XMLEncoder}.
206  *
207  *
208  * @beaninfo
209  *   attribute: isContainer false
210  * description: A component which displays data in a two dimensional grid.
211  *
212  * @author Philip Milne
213  * @author Shannon Hickey (printing support)
214  * @see javax.swing.table.DefaultTableModel
215  * @see javax.swing.table.TableRowSorter
216  */
217 /* The first versions of the JTable, contained in Swing-0.1 through
218  * Swing-0.4, were written by Alan Chung.
219  */
220 public class JTable extends JComponent implements TableModelListener, Scrollable,
221     TableColumnModelListener, ListSelectionListener, CellEditorListener,
222     Accessible, RowSorterListener
223 {
224 //
225 // Static Constants
226 //
227 
228     /**
229      * @see #getUIClassID
230      * @see #readObject
231      */
232     private static final String uiClassID = "TableUI";
233 
234     /** Do not adjust column widths automatically; use a horizontal scrollbar instead. */
235     public static final int     AUTO_RESIZE_OFF = 0;
236 
237     /** When a column is adjusted in the UI, adjust the next column the opposite way. */
238     public static final int     AUTO_RESIZE_NEXT_COLUMN = 1;
239 
240     /** During UI adjustment, change subsequent columns to preserve the total width;
241       * this is the default behavior. */
242     public static final int     AUTO_RESIZE_SUBSEQUENT_COLUMNS = 2;
243 
244     /** During all resize operations, apply adjustments to the last column only. */
245     public static final int     AUTO_RESIZE_LAST_COLUMN = 3;
246 
247     /** During all resize operations, proportionately resize all columns. */
248     public static final int     AUTO_RESIZE_ALL_COLUMNS = 4;
249 
250 
251     /**
252      * Printing modes, used in printing <code>JTable</code>s.
253      *
254      * @see #print(JTable.PrintMode, MessageFormat, MessageFormat,
255      *             boolean, PrintRequestAttributeSet, boolean)
256      * @see #getPrintable
257      * @since 1.5
258      */
259     public enum PrintMode {
260 
261         /**
262          * Printing mode that prints the table at its current size,
263          * spreading both columns and rows across multiple pages if necessary.
264          */
265         NORMAL,
266 
267         /**
268          * Printing mode that scales the output smaller, if necessary,
269          * to fit the table's entire width (and thereby all columns) on each page;
270          * Rows are spread across multiple pages as necessary.
271          */
272         FIT_WIDTH
273     }
274 
275 
276 //
277 // Instance Variables
278 //
279 
280     /** The <code>TableModel</code> of the table. */
281     protected TableModel        dataModel;
282 
283     /** The <code>TableColumnModel</code> of the table. */
284     protected TableColumnModel  columnModel;
285 
286     /** The <code>ListSelectionModel</code> of the table, used to keep track of row selections. */
287     protected ListSelectionModel selectionModel;
288 
289     /** The <code>TableHeader</code> working with the table. */
290     protected JTableHeader      tableHeader;
291 
292     /** The height in pixels of each row in the table. */
293     protected int               rowHeight;
294 
295     /** The height in pixels of the margin between the cells in each row. */
296     protected int               rowMargin;
297 
298     /** The color of the grid. */
299     protected Color             gridColor;
300 
301     /** The table draws horizontal lines between cells if <code>showHorizontalLines</code> is true. */
302     protected boolean           showHorizontalLines;
303 
304     /** The table draws vertical lines between cells if <code>showVerticalLines</code> is true. */
305     protected boolean           showVerticalLines;
306 
307     /**
308      *  Determines if the table automatically resizes the
309      *  width of the table's columns to take up the entire width of the
310      *  table, and how it does the resizing.
311      */
312     protected int               autoResizeMode;
313 
314     /**
315      *  The table will query the <code>TableModel</code> to build the default
316      *  set of columns if this is true.
317      */
318     protected boolean           autoCreateColumnsFromModel;
319 
320     /** Used by the <code>Scrollable</code> interface to determine the initial visible area. */
321     protected Dimension         preferredViewportSize;
322 
323     /** True if row selection is allowed in this table. */
324     protected boolean           rowSelectionAllowed;
325 
326     /**
327      * Obsolete as of Java 2 platform v1.3.  Please use the
328      * <code>rowSelectionAllowed</code> property and the
329      * <code>columnSelectionAllowed</code> property of the
330      * <code>columnModel</code> instead. Or use the
331      * method <code>getCellSelectionEnabled</code>.
332      */
333     /*
334      * If true, both a row selection and a column selection
335      * can be non-empty at the same time, the selected cells are the
336      * the cells whose row and column are both selected.
337      */
338     protected boolean           cellSelectionEnabled;
339 
340     /** If editing, the <code>Component</code> that is handling the editing. */
341     transient protected Component       editorComp;
342 
343     /**
344      * The active cell editor object, that overwrites the screen real estate
345      * occupied by the current cell and allows the user to change its contents.
346      * {@code null} if the table isn't currently editing.
347      */
348     transient protected TableCellEditor cellEditor;
349 
350     /** Identifies the column of the cell being edited. */
351     transient protected int             editingColumn;
352 
353     /** Identifies the row of the cell being edited. */
354     transient protected int             editingRow;
355 
356     /**
357      * A table of objects that display the contents of a cell,
358      * indexed by class as declared in <code>getColumnClass</code>
359      * in the <code>TableModel</code> interface.
360      */
361     transient protected Hashtable defaultRenderersByColumnClass;
362 
363     /**
364      * A table of objects that display and edit the contents of a cell,
365      * indexed by class as declared in <code>getColumnClass</code>
366      * in the <code>TableModel</code> interface.
367      */
368     transient protected Hashtable defaultEditorsByColumnClass;
369 
370     /** The foreground color of selected cells. */
371     protected Color selectionForeground;
372 
373     /** The background color of selected cells. */
374     protected Color selectionBackground;
375 
376 //
377 // Private state
378 //
379 
380     // WARNING: If you directly access this field you should also change the
381     // SortManager.modelRowSizes field as well.
382     private SizeSequence rowModel;
383     private boolean dragEnabled;
384     private boolean surrendersFocusOnKeystroke;
385     private PropertyChangeListener editorRemover = null;
386     /**
387      * The last value of getValueIsAdjusting from the column selection models
388      * columnSelectionChanged notification. Used to test if a repaint is
389      * needed.
390      */
391     private boolean columnSelectionAdjusting;
392     /**
393      * The last value of getValueIsAdjusting from the row selection models
394      * valueChanged notification. Used to test if a repaint is needed.
395      */
396     private boolean rowSelectionAdjusting;
397 
398     /**
399      * To communicate errors between threads during printing.
400      */
401     private Throwable printError;
402 
403     /**
404      * True when setRowHeight(int) has been invoked.
405      */
406     private boolean isRowHeightSet;
407 
408     /**
409      * If true, on a sort the selection is reset.
410      */
411     private boolean updateSelectionOnSort;
412 
413     /**
414      * Information used in sorting.
415      */
416     private transient SortManager sortManager;
417 
418     /**
419      * If true, when sorterChanged is invoked it's value is ignored.
420      */
421     private boolean ignoreSortChange;
422 
423     /**
424      * Whether or not sorterChanged has been invoked.
425      */
426     private boolean sorterChanged;
427 
428     /**
429      * If true, any time the model changes a new RowSorter is set.
430      */
431     private boolean autoCreateRowSorter;
432 
433     /**
434      * Whether or not the table always fills the viewport height.
435      * @see #setFillsViewportHeight
436      * @see #getScrollableTracksViewportHeight
437      */
438     private boolean fillsViewportHeight;
439 
440     /**
441      * The drop mode for this component.
442      */
443     private DropMode dropMode = DropMode.USE_SELECTION;
444 
445     /**
446      * The drop location.
447      */
448     private transient DropLocation dropLocation;
449 
450     /**
451      * A subclass of <code>TransferHandler.DropLocation</code> representing
452      * a drop location for a <code>JTable</code>.
453      *
454      * @see #getDropLocation
455      * @since 1.6
456      */
457     public static final class DropLocation extends TransferHandler.DropLocation {
458         private final int row;
459         private final int col;
460         private final boolean isInsertRow;
461         private final boolean isInsertCol;
462 
463         private DropLocation(Point p, int row, int col,
464                              boolean isInsertRow, boolean isInsertCol) {
465 
466             super(p);
467             this.row = row;
468             this.col = col;
469             this.isInsertRow = isInsertRow;
470             this.isInsertCol = isInsertCol;
471         }
472 
473         /**
474          * Returns the row index where a dropped item should be placed in the
475          * table. Interpretation of the value depends on the return of
476          * <code>isInsertRow()</code>. If that method returns
477          * <code>true</code> this value indicates the index where a new
478          * row should be inserted. Otherwise, it represents the value
479          * of an existing row on which the data was dropped. This index is
480          * in terms of the view.
481          * <p>
482          * <code>-1</code> indicates that the drop occurred over empty space,
483          * and no row could be calculated.
484          *
485          * @return the drop row
486          */
487         public int getRow() {
488             return row;
489         }
490 
491         /**
492          * Returns the column index where a dropped item should be placed in the
493          * table. Interpretation of the value depends on the return of
494          * <code>isInsertColumn()</code>. If that method returns
495          * <code>true</code> this value indicates the index where a new
496          * column should be inserted. Otherwise, it represents the value
497          * of an existing column on which the data was dropped. This index is
498          * in terms of the view.
499          * <p>
500          * <code>-1</code> indicates that the drop occurred over empty space,
501          * and no column could be calculated.
502          *
503          * @return the drop row
504          */
505         public int getColumn() {
506             return col;
507         }
508 
509         /**
510          * Returns whether or not this location represents an insert
511          * of a row.
512          *
513          * @return whether or not this is an insert row
514          */
515         public boolean isInsertRow() {
516             return isInsertRow;
517         }
518 
519         /**
520          * Returns whether or not this location represents an insert
521          * of a column.
522          *
523          * @return whether or not this is an insert column
524          */
525         public boolean isInsertColumn() {
526             return isInsertCol;
527         }
528 
529         /**
530          * Returns a string representation of this drop location.
531          * This method is intended to be used for debugging purposes,
532          * and the content and format of the returned string may vary
533          * between implementations.
534          *
535          * @return a string representation of this drop location
536          */
537         public String toString() {
538             return getClass().getName()
539                    + "[dropPoint=" + getDropPoint() + ","
540                    + "row=" + row + ","
541                    + "column=" + col + ","
542                    + "insertRow=" + isInsertRow + ","
543                    + "insertColumn=" + isInsertCol + "]";
544         }
545     }
546 
547 //
548 // Constructors
549 //
550 
551     /**
552      * Constructs a default <code>JTable</code> that is initialized with a default
553      * data model, a default column model, and a default selection
554      * model.
555      *
556      * @see #createDefaultDataModel
557      * @see #createDefaultColumnModel
558      * @see #createDefaultSelectionModel
559      */
560     public JTable() {
561         this(null, null, null);
562     }
563 
564     /**
565      * Constructs a <code>JTable</code> that is initialized with
566      * <code>dm</code> as the data model, a default column model,
567      * and a default selection model.
568      *
569      * @param dm        the data model for the table
570      * @see #createDefaultColumnModel
571      * @see #createDefaultSelectionModel
572      */
573     public JTable(TableModel dm) {
574         this(dm, null, null);
575     }
576 
577     /**
578      * Constructs a <code>JTable</code> that is initialized with
579      * <code>dm</code> as the data model, <code>cm</code>
580      * as the column model, and a default selection model.
581      *
582      * @param dm        the data model for the table
583      * @param cm        the column model for the table
584      * @see #createDefaultSelectionModel
585      */
586     public JTable(TableModel dm, TableColumnModel cm) {
587         this(dm, cm, null);
588     }
589 
590     /**
591      * Constructs a <code>JTable</code> that is initialized with
592      * <code>dm</code> as the data model, <code>cm</code> as the
593      * column model, and <code>sm</code> as the selection model.
594      * If any of the parameters are <code>null</code> this method
595      * will initialize the table with the corresponding default model.
596      * The <code>autoCreateColumnsFromModel</code> flag is set to false
597      * if <code>cm</code> is non-null, otherwise it is set to true
598      * and the column model is populated with suitable
599      * <code>TableColumns</code> for the columns in <code>dm</code>.
600      *
601      * @param dm        the data model for the table
602      * @param cm        the column model for the table
603      * @param sm        the row selection model for the table
604      * @see #createDefaultDataModel
605      * @see #createDefaultColumnModel
606      * @see #createDefaultSelectionModel
607      */
608     public JTable(TableModel dm, TableColumnModel cm, ListSelectionModel sm) {
609         super();
610         setLayout(null);
611 
612         setFocusTraversalKeys(KeyboardFocusManager.FORWARD_TRAVERSAL_KEYS,
613                            JComponent.getManagingFocusForwardTraversalKeys());
614         setFocusTraversalKeys(KeyboardFocusManager.BACKWARD_TRAVERSAL_KEYS,
615                            JComponent.getManagingFocusBackwardTraversalKeys());
616         if (cm == null) {
617             cm = createDefaultColumnModel();
618             autoCreateColumnsFromModel = true;
619         }
620         setColumnModel(cm);
621 
622         if (sm == null) {
623             sm = createDefaultSelectionModel();
624         }
625         setSelectionModel(sm);
626 
627     // Set the model last, that way if the autoCreatColumnsFromModel has
628     // been set above, we will automatically populate an empty columnModel
629     // with suitable columns for the new model.
630         if (dm == null) {
631             dm = createDefaultDataModel();
632         }
633         setModel(dm);
634 
635         initializeLocalVars();
636         updateUI();
637     }
638 
639     /**
640      * Constructs a <code>JTable</code> with <code>numRows</code>
641      * and <code>numColumns</code> of empty cells using
642      * <code>DefaultTableModel</code>.  The columns will have
643      * names of the form "A", "B", "C", etc.
644      *
645      * @param numRows           the number of rows the table holds
646      * @param numColumns        the number of columns the table holds
647      * @see javax.swing.table.DefaultTableModel
648      */
649     public JTable(int numRows, int numColumns) {
650         this(new DefaultTableModel(numRows, numColumns));
651     }
652 
653     /**
654      * Constructs a <code>JTable</code> to display the values in the
655      * <code>Vector</code> of <code>Vectors</code>, <code>rowData</code>,
656      * with column names, <code>columnNames</code>.  The
657      * <code>Vectors</code> contained in <code>rowData</code>
658      * should contain the values for that row. In other words,
659      * the value of the cell at row 1, column 5 can be obtained
660      * with the following code:
661      * <p>
662      * <pre>((Vector)rowData.elementAt(1)).elementAt(5);</pre>
663      * <p>
664      * @param rowData           the data for the new table
665      * @param columnNames       names of each column
666      */
667     public JTable(Vector rowData, Vector columnNames) {
668         this(new DefaultTableModel(rowData, columnNames));
669     }
670 
671     /**
672      * Constructs a <code>JTable</code> to display the values in the two dimensional array,
673      * <code>rowData</code>, with column names, <code>columnNames</code>.
674      * <code>rowData</code> is an array of rows, so the value of the cell at row 1,
675      * column 5 can be obtained with the following code:
676      * <p>
677      * <pre> rowData[1][5]; </pre>
678      * <p>
679      * All rows must be of the same length as <code>columnNames</code>.
680      * <p>
681      * @param rowData           the data for the new table
682      * @param columnNames       names of each column
683      */
684     public JTable(final Object[][] rowData, final Object[] columnNames) {
685         this(new AbstractTableModel() {
686             public String getColumnName(int column) { return columnNames[column].toString(); }
687             public int getRowCount() { return rowData.length; }
688             public int getColumnCount() { return columnNames.length; }
689             public Object getValueAt(int row, int col) { return rowData[row][col]; }
690             public boolean isCellEditable(int row, int column) { return true; }
691             public void setValueAt(Object value, int row, int col) {
692                 rowData[row][col] = value;
693                 fireTableCellUpdated(row, col);
694             }
695         });
696     }
697 
698     /**
699      * Calls the <code>configureEnclosingScrollPane</code> method.
700      *
701      * @see #configureEnclosingScrollPane
702      */
703     public void addNotify() {
704         super.addNotify();
705         configureEnclosingScrollPane();
706     }
707 
708     /**
709      * If this <code>JTable</code> is the <code>viewportView</code> of an enclosing <code>JScrollPane</code>
710      * (the usual situation), configure this <code>ScrollPane</code> by, amongst other things,
711      * installing the table's <code>tableHeader</code> as the <code>columnHeaderView</code> of the scroll pane.
712      * When a <code>JTable</code> is added to a <code>JScrollPane</code> in the usual way,
713      * using <code>new JScrollPane(myTable)</code>, <code>addNotify</code> is
714      * called in the <code>JTable</code> (when the table is added to the viewport).
715      * <code>JTable</code>'s <code>addNotify</code> method in turn calls this method,
716      * which is protected so that this default installation procedure can
717      * be overridden by a subclass.
718      *
719      * @see #addNotify
720      */
721     protected void configureEnclosingScrollPane() {
722         Container parent = SwingUtilities.getUnwrappedParent(this);
723         if (parent instanceof JViewport) {
724             JViewport port = (JViewport) parent;
725             Container gp = port.getParent();
726             if (gp instanceof JScrollPane) {
727                 JScrollPane scrollPane = (JScrollPane)gp;
728                 // Make certain we are the viewPort's view and not, for
729                 // example, the rowHeaderView of the scrollPane -
730                 // an implementor of fixed columns might do this.
731                 JViewport viewport = scrollPane.getViewport();
732                 if (viewport == null ||
733                         SwingUtilities.getUnwrappedView(viewport) != this) {
734                     return;
735                 }
736                 scrollPane.setColumnHeaderView(getTableHeader());
737                 // configure the scrollpane for any LAF dependent settings
738                 configureEnclosingScrollPaneUI();
739             }
740         }
741     }
742 
743     /**
744      * This is a sub-part of configureEnclosingScrollPane() that configures
745      * anything on the scrollpane that may change when the look and feel
746      * changes. It needed to be split out from configureEnclosingScrollPane() so
747      * that it can be called from updateUI() when the LAF changes without
748      * causing the regression found in bug 6687962. This was because updateUI()
749      * is called from the constructor which then caused
750      * configureEnclosingScrollPane() to be called by the constructor which
751      * changes its contract for any subclass that overrides it. So by splitting
752      * it out in this way configureEnclosingScrollPaneUI() can be called both
753      * from configureEnclosingScrollPane() and updateUI() in a safe manor.
754      */
755     private void configureEnclosingScrollPaneUI() {
756         Container parent = SwingUtilities.getUnwrappedParent(this);
757         if (parent instanceof JViewport) {
758             JViewport port = (JViewport) parent;
759             Container gp = port.getParent();
760             if (gp instanceof JScrollPane) {
761                 JScrollPane scrollPane = (JScrollPane)gp;
762                 // Make certain we are the viewPort's view and not, for
763                 // example, the rowHeaderView of the scrollPane -
764                 // an implementor of fixed columns might do this.
765                 JViewport viewport = scrollPane.getViewport();
766                 if (viewport == null ||
767                         SwingUtilities.getUnwrappedView(viewport) != this) {
768                     return;
769                 }
770                 //  scrollPane.getViewport().setBackingStoreEnabled(true);
771                 Border border = scrollPane.getBorder();
772                 if (border == null || border instanceof UIResource) {
773                     Border scrollPaneBorder =
774                         UIManager.getBorder("Table.scrollPaneBorder");
775                     if (scrollPaneBorder != null) {
776                         scrollPane.setBorder(scrollPaneBorder);
777                     }
778                 }
779                 // add JScrollBar corner component if available from LAF and not already set by the user
780                 Component corner =
781                         scrollPane.getCorner(JScrollPane.UPPER_TRAILING_CORNER);
782                 if (corner == null || corner instanceof UIResource){
783                     corner = null;
784                     Object componentClass = UIManager.get(
785                             "Table.scrollPaneCornerComponent");
786                     if (componentClass instanceof Class){
787                         try {
788                             corner = (Component)
789                                     ((Class)componentClass).newInstance();
790                         } catch (Exception e) {
791                             // just ignore and don't set corner
792                         }
793                     }
794                     scrollPane.setCorner(JScrollPane.UPPER_TRAILING_CORNER,
795                             corner);
796                 }
797             }
798         }
799     }
800 
801     /**
802      * Calls the <code>unconfigureEnclosingScrollPane</code> method.
803      *
804      * @see #unconfigureEnclosingScrollPane
805      */
806     public void removeNotify() {
807         KeyboardFocusManager.getCurrentKeyboardFocusManager().
808             removePropertyChangeListener("permanentFocusOwner", editorRemover);
809         editorRemover = null;
810         unconfigureEnclosingScrollPane();
811         super.removeNotify();
812     }
813 
814     /**
815      * Reverses the effect of <code>configureEnclosingScrollPane</code>
816      * by replacing the <code>columnHeaderView</code> of the enclosing
817      * scroll pane with <code>null</code>. <code>JTable</code>'s
818      * <code>removeNotify</code> method calls
819      * this method, which is protected so that this default uninstallation
820      * procedure can be overridden by a subclass.
821      *
822      * @see #removeNotify
823      * @see #configureEnclosingScrollPane
824      * @since 1.3
825      */
826     protected void unconfigureEnclosingScrollPane() {
827         Container parent = SwingUtilities.getUnwrappedParent(this);
828         if (parent instanceof JViewport) {
829             JViewport port = (JViewport) parent;
830             Container gp = port.getParent();
831             if (gp instanceof JScrollPane) {
832                 JScrollPane scrollPane = (JScrollPane)gp;
833                 // Make certain we are the viewPort's view and not, for
834                 // example, the rowHeaderView of the scrollPane -
835                 // an implementor of fixed columns might do this.
836                 JViewport viewport = scrollPane.getViewport();
837                 if (viewport == null ||
838                         SwingUtilities.getUnwrappedView(viewport) != this) {
839                     return;
840                 }
841                 scrollPane.setColumnHeaderView(null);
842                 // remove ScrollPane corner if one was added by the LAF
843                 Component corner =
844                         scrollPane.getCorner(JScrollPane.UPPER_TRAILING_CORNER);
845                 if (corner instanceof UIResource){
846                     scrollPane.setCorner(JScrollPane.UPPER_TRAILING_CORNER,
847                             null);
848                 }
849             }
850         }
851     }
852 
853     void setUIProperty(String propertyName, Object value) {
854         if (propertyName == "rowHeight") {
855             if (!isRowHeightSet) {
856                 setRowHeight(((Number)value).intValue());
857                 isRowHeightSet = false;
858             }
859             return;
860         }
861         super.setUIProperty(propertyName, value);
862     }
863 
864 //
865 // Static Methods
866 //
867 
868     /**
869      * Equivalent to <code>new JScrollPane(aTable)</code>.
870      *
871      * @deprecated As of Swing version 1.0.2,
872      * replaced by <code>new JScrollPane(aTable)</code>.
873      */
874     @Deprecated
875     static public JScrollPane createScrollPaneForTable(JTable aTable) {
876         return new JScrollPane(aTable);
877     }
878 
879 //
880 // Table Attributes
881 //
882 
883     /**
884      * Sets the <code>tableHeader</code> working with this <code>JTable</code> to <code>newHeader</code>.
885      * It is legal to have a <code>null</code> <code>tableHeader</code>.
886      *
887      * @param   tableHeader                       new tableHeader
888      * @see     #getTableHeader
889      * @beaninfo
890      *  bound: true
891      *  description: The JTableHeader instance which renders the column headers.
892      */
893     public void setTableHeader(JTableHeader tableHeader) {
894         if (this.tableHeader != tableHeader) {
895             JTableHeader old = this.tableHeader;
896             // Release the old header
897             if (old != null) {
898                 old.setTable(null);
899             }
900             this.tableHeader = tableHeader;
901             if (tableHeader != null) {
902                 tableHeader.setTable(this);
903             }
904             firePropertyChange("tableHeader", old, tableHeader);
905         }
906     }
907 
908     /**
909      * Returns the <code>tableHeader</code> used by this <code>JTable</code>.
910      *
911      * @return  the <code>tableHeader</code> used by this table
912      * @see     #setTableHeader
913      */
914     public JTableHeader getTableHeader() {
915         return tableHeader;
916     }
917 
918     /**
919      * Sets the height, in pixels, of all cells to <code>rowHeight</code>,
920      * revalidates, and repaints.
921      * The height of the cells will be equal to the row height minus
922      * the row margin.
923      *
924      * @param   rowHeight                       new row height
925      * @exception IllegalArgumentException      if <code>rowHeight</code> is
926      *                                          less than 1
927      * @see     #getRowHeight
928      * @beaninfo
929      *  bound: true
930      *  description: The height of the specified row.
931      */
932     public void setRowHeight(int rowHeight) {
933         if (rowHeight <= 0) {
934             throw new IllegalArgumentException("New row height less than 1");
935         }
936         int old = this.rowHeight;
937         this.rowHeight = rowHeight;
938         rowModel = null;
939         if (sortManager != null) {
940             sortManager.modelRowSizes = null;
941         }
942         isRowHeightSet = true;
943         resizeAndRepaint();
944         firePropertyChange("rowHeight", old, rowHeight);
945     }
946 
947     /**
948      * Returns the height of a table row, in pixels.
949      *
950      * @return  the height in pixels of a table row
951      * @see     #setRowHeight
952      */
953     public int getRowHeight() {
954         return rowHeight;
955     }
956 
957     private SizeSequence getRowModel() {
958         if (rowModel == null) {
959             rowModel = new SizeSequence(getRowCount(), getRowHeight());
960         }
961         return rowModel;
962     }
963 
964     /**
965      * Sets the height for <code>row</code> to <code>rowHeight</code>,
966      * revalidates, and repaints. The height of the cells in this row
967      * will be equal to the row height minus the row margin.
968      *
969      * @param   row                             the row whose height is being
970                                                 changed
971      * @param   rowHeight                       new row height, in pixels
972      * @exception IllegalArgumentException      if <code>rowHeight</code> is
973      *                                          less than 1
974      * @beaninfo
975      *  bound: true
976      *  description: The height in pixels of the cells in <code>row</code>
977      * @since 1.3
978      */
979     public void setRowHeight(int row, int rowHeight) {
980         if (rowHeight <= 0) {
981             throw new IllegalArgumentException("New row height less than 1");
982         }
983         getRowModel().setSize(row, rowHeight);
984         if (sortManager != null) {
985             sortManager.setViewRowHeight(row, rowHeight);
986         }
987         resizeAndRepaint();
988     }
989 
990     /**
991      * Returns the height, in pixels, of the cells in <code>row</code>.
992      * @param   row              the row whose height is to be returned
993      * @return the height, in pixels, of the cells in the row
994      * @since 1.3
995      */
996     public int getRowHeight(int row) {
997         return (rowModel == null) ? getRowHeight() : rowModel.getSize(row);
998     }
999 
1000     /**
1001      * Sets the amount of empty space between cells in adjacent rows.
1002      *
1003      * @param  rowMargin  the number of pixels between cells in a row
1004      * @see     #getRowMargin
1005      * @beaninfo
1006      *  bound: true
1007      *  description: The amount of space between cells.
1008      */
1009     public void setRowMargin(int rowMargin) {
1010         int old = this.rowMargin;
1011         this.rowMargin = rowMargin;
1012         resizeAndRepaint();
1013         firePropertyChange("rowMargin", old, rowMargin);
1014     }
1015 
1016     /**
1017      * Gets the amount of empty space, in pixels, between cells. Equivalent to:
1018      * <code>getIntercellSpacing().height</code>.
1019      * @return the number of pixels between cells in a row
1020      *
1021      * @see     #setRowMargin
1022      */
1023     public int getRowMargin() {
1024         return rowMargin;
1025     }
1026 
1027     /**
1028      * Sets the <code>rowMargin</code> and the <code>columnMargin</code> --
1029      * the height and width of the space between cells -- to
1030      * <code>intercellSpacing</code>.
1031      *
1032      * @param   intercellSpacing        a <code>Dimension</code>
1033      *                                  specifying the new width
1034      *                                  and height between cells
1035      * @see     #getIntercellSpacing
1036      * @beaninfo
1037      *  description: The spacing between the cells,
1038      *               drawn in the background color of the JTable.
1039      */
1040     public void setIntercellSpacing(Dimension intercellSpacing) {
1041         // Set the rowMargin here and columnMargin in the TableColumnModel
1042         setRowMargin(intercellSpacing.height);
1043         getColumnModel().setColumnMargin(intercellSpacing.width);
1044 
1045         resizeAndRepaint();
1046     }
1047 
1048     /**
1049      * Returns the horizontal and vertical space between cells.
1050      * The default spacing is look and feel dependent.
1051      *
1052      * @return  the horizontal and vertical spacing between cells
1053      * @see     #setIntercellSpacing
1054      */
1055     public Dimension getIntercellSpacing() {
1056         return new Dimension(getColumnModel().getColumnMargin(), rowMargin);
1057     }
1058 
1059     /**
1060      * Sets the color used to draw grid lines to <code>gridColor</code> and redisplays.
1061      * The default color is look and feel dependent.
1062      *
1063      * @param   gridColor                       the new color of the grid lines
1064      * @exception IllegalArgumentException      if <code>gridColor</code> is <code>null</code>
1065      * @see     #getGridColor
1066      * @beaninfo
1067      *  bound: true
1068      *  description: The grid color.
1069      */
1070     public void setGridColor(Color gridColor) {
1071         if (gridColor == null) {
1072             throw new IllegalArgumentException("New color is null");
1073         }
1074         Color old = this.gridColor;
1075         this.gridColor = gridColor;
1076         firePropertyChange("gridColor", old, gridColor);
1077         // Redraw
1078         repaint();
1079     }
1080 
1081     /**
1082      * Returns the color used to draw grid lines.
1083      * The default color is look and feel dependent.
1084      *
1085      * @return  the color used to draw grid lines
1086      * @see     #setGridColor
1087      */
1088     public Color getGridColor() {
1089         return gridColor;
1090     }
1091 
1092     /**
1093      *  Sets whether the table draws grid lines around cells.
1094      *  If <code>showGrid</code> is true it does; if it is false it doesn't.
1095      *  There is no <code>getShowGrid</code> method as this state is held
1096      *  in two variables -- <code>showHorizontalLines</code> and <code>showVerticalLines</code> --
1097      *  each of which can be queried independently.
1098      *
1099      * @param   showGrid                 true if table view should draw grid lines
1100      *
1101      * @see     #setShowVerticalLines
1102      * @see     #setShowHorizontalLines
1103      * @beaninfo
1104      *  description: The color used to draw the grid lines.
1105      */
1106     public void setShowGrid(boolean showGrid) {
1107         setShowHorizontalLines(showGrid);
1108         setShowVerticalLines(showGrid);
1109 
1110         // Redraw
1111         repaint();
1112     }
1113 
1114     /**
1115      *  Sets whether the table draws horizontal lines between cells.
1116      *  If <code>showHorizontalLines</code> is true it does; if it is false it doesn't.
1117      *
1118      * @param   showHorizontalLines      true if table view should draw horizontal lines
1119      * @see     #getShowHorizontalLines
1120      * @see     #setShowGrid
1121      * @see     #setShowVerticalLines
1122      * @beaninfo
1123      *  bound: true
1124      *  description: Whether horizontal lines should be drawn in between the cells.
1125      */
1126     public void setShowHorizontalLines(boolean showHorizontalLines) {
1127         boolean old = this.showHorizontalLines;
1128         this.showHorizontalLines = showHorizontalLines;
1129         firePropertyChange("showHorizontalLines", old, showHorizontalLines);
1130 
1131         // Redraw
1132         repaint();
1133     }
1134 
1135     /**
1136      *  Sets whether the table draws vertical lines between cells.
1137      *  If <code>showVerticalLines</code> is true it does; if it is false it doesn't.
1138      *
1139      * @param   showVerticalLines              true if table view should draw vertical lines
1140      * @see     #getShowVerticalLines
1141      * @see     #setShowGrid
1142      * @see     #setShowHorizontalLines
1143      * @beaninfo
1144      *  bound: true
1145      *  description: Whether vertical lines should be drawn in between the cells.
1146      */
1147     public void setShowVerticalLines(boolean showVerticalLines) {
1148         boolean old = this.showVerticalLines;
1149         this.showVerticalLines = showVerticalLines;
1150         firePropertyChange("showVerticalLines", old, showVerticalLines);
1151         // Redraw
1152         repaint();
1153     }
1154 
1155     /**
1156      * Returns true if the table draws horizontal lines between cells, false if it
1157      * doesn't. The default value is look and feel dependent.
1158      *
1159      * @return  true if the table draws horizontal lines between cells, false if it
1160      *          doesn't
1161      * @see     #setShowHorizontalLines
1162      */
1163     public boolean getShowHorizontalLines() {
1164         return showHorizontalLines;
1165     }
1166 
1167     /**
1168      * Returns true if the table draws vertical lines between cells, false if it
1169      * doesn't. The default value is look and feel dependent.
1170      *
1171      * @return  true if the table draws vertical lines between cells, false if it
1172      *          doesn't
1173      * @see     #setShowVerticalLines
1174      */
1175     public boolean getShowVerticalLines() {
1176         return showVerticalLines;
1177     }
1178 
1179     /**
1180      * Sets the table's auto resize mode when the table is resized.  For further
1181      * information on how the different resize modes work, see
1182      * {@link #doLayout}.
1183      *
1184      * @param   mode One of 5 legal values:
1185      *                   AUTO_RESIZE_OFF,
1186      *                   AUTO_RESIZE_NEXT_COLUMN,
1187      *                   AUTO_RESIZE_SUBSEQUENT_COLUMNS,
1188      *                   AUTO_RESIZE_LAST_COLUMN,
1189      *                   AUTO_RESIZE_ALL_COLUMNS
1190      *
1191      * @see     #getAutoResizeMode
1192      * @see     #doLayout
1193      * @beaninfo
1194      *  bound: true
1195      *  description: Whether the columns should adjust themselves automatically.
1196      *        enum: AUTO_RESIZE_OFF                JTable.AUTO_RESIZE_OFF
1197      *              AUTO_RESIZE_NEXT_COLUMN        JTable.AUTO_RESIZE_NEXT_COLUMN
1198      *              AUTO_RESIZE_SUBSEQUENT_COLUMNS JTable.AUTO_RESIZE_SUBSEQUENT_COLUMNS
1199      *              AUTO_RESIZE_LAST_COLUMN        JTable.AUTO_RESIZE_LAST_COLUMN
1200      *              AUTO_RESIZE_ALL_COLUMNS        JTable.AUTO_RESIZE_ALL_COLUMNS
1201      */
1202     public void setAutoResizeMode(int mode) {
1203         if ((mode == AUTO_RESIZE_OFF) ||
1204             (mode == AUTO_RESIZE_NEXT_COLUMN) ||
1205             (mode == AUTO_RESIZE_SUBSEQUENT_COLUMNS) ||
1206             (mode == AUTO_RESIZE_LAST_COLUMN) ||
1207             (mode == AUTO_RESIZE_ALL_COLUMNS)) {
1208             int old = autoResizeMode;
1209             autoResizeMode = mode;
1210             resizeAndRepaint();
1211             if (tableHeader != null) {
1212                 tableHeader.resizeAndRepaint();
1213             }
1214             firePropertyChange("autoResizeMode", old, autoResizeMode);
1215         }
1216     }
1217 
1218     /**
1219      * Returns the auto resize mode of the table.  The default mode
1220      * is AUTO_RESIZE_SUBSEQUENT_COLUMNS.
1221      *
1222      * @return  the autoResizeMode of the table
1223      *
1224      * @see     #setAutoResizeMode
1225      * @see     #doLayout
1226      */
1227     public int getAutoResizeMode() {
1228         return autoResizeMode;
1229     }
1230 
1231     /**
1232      * Sets this table's <code>autoCreateColumnsFromModel</code> flag.
1233      * This method calls <code>createDefaultColumnsFromModel</code> if
1234      * <code>autoCreateColumnsFromModel</code> changes from false to true.
1235      *
1236      * @param   autoCreateColumnsFromModel   true if <code>JTable</code> should automatically create columns
1237      * @see     #getAutoCreateColumnsFromModel
1238      * @see     #createDefaultColumnsFromModel
1239      * @beaninfo
1240      *  bound: true
1241      *  description: Automatically populates the columnModel when a new TableModel is submitted.
1242      */
1243     public void setAutoCreateColumnsFromModel(boolean autoCreateColumnsFromModel) {
1244         if (this.autoCreateColumnsFromModel != autoCreateColumnsFromModel) {
1245             boolean old = this.autoCreateColumnsFromModel;
1246             this.autoCreateColumnsFromModel = autoCreateColumnsFromModel;
1247             if (autoCreateColumnsFromModel) {
1248                 createDefaultColumnsFromModel();
1249             }
1250             firePropertyChange("autoCreateColumnsFromModel", old, autoCreateColumnsFromModel);
1251         }
1252     }
1253 
1254     /**
1255      * Determines whether the table will create default columns from the model.
1256      * If true, <code>setModel</code> will clear any existing columns and
1257      * create new columns from the new model.  Also, if the event in
1258      * the <code>tableChanged</code> notification specifies that the
1259      * entire table changed, then the columns will be rebuilt.
1260      * The default is true.
1261      *
1262      * @return  the autoCreateColumnsFromModel of the table
1263      * @see     #setAutoCreateColumnsFromModel
1264      * @see     #createDefaultColumnsFromModel
1265      */
1266     public boolean getAutoCreateColumnsFromModel() {
1267         return autoCreateColumnsFromModel;
1268     }
1269 
1270     /**
1271      * Creates default columns for the table from
1272      * the data model using the <code>getColumnCount</code> method
1273      * defined in the <code>TableModel</code> interface.
1274      * <p>
1275      * Clears any existing columns before creating the
1276      * new columns based on information from the model.
1277      *
1278      * @see     #getAutoCreateColumnsFromModel
1279      */
1280     public void createDefaultColumnsFromModel() {
1281         TableModel m = getModel();
1282         if (m != null) {
1283             // Remove any current columns
1284             TableColumnModel cm = getColumnModel();
1285             while (cm.getColumnCount() > 0) {
1286                 cm.removeColumn(cm.getColumn(0));
1287             }
1288 
1289             // Create new columns from the data model info
1290             for (int i = 0; i < m.getColumnCount(); i++) {
1291                 TableColumn newColumn = new TableColumn(i);
1292                 addColumn(newColumn);
1293             }
1294         }
1295     }
1296 
1297     /**
1298      * Sets a default cell renderer to be used if no renderer has been set in
1299      * a <code>TableColumn</code>. If renderer is <code>null</code>,
1300      * removes the default renderer for this column class.
1301      *
1302      * @param  columnClass     set the default cell renderer for this columnClass
1303      * @param  renderer        default cell renderer to be used for this
1304      *                         columnClass
1305      * @see     #getDefaultRenderer
1306      * @see     #setDefaultEditor
1307      */
1308     public void setDefaultRenderer(Class<?> columnClass, TableCellRenderer renderer) {
1309         if (renderer != null) {
1310             defaultRenderersByColumnClass.put(columnClass, renderer);
1311         }
1312         else {
1313             defaultRenderersByColumnClass.remove(columnClass);
1314         }
1315     }
1316 
1317     /**
1318      * Returns the cell renderer to be used when no renderer has been set in
1319      * a <code>TableColumn</code>. During the rendering of cells the renderer is fetched from
1320      * a <code>Hashtable</code> of entries according to the class of the cells in the column. If
1321      * there is no entry for this <code>columnClass</code> the method returns
1322      * the entry for the most specific superclass. The <code>JTable</code> installs entries
1323      * for <code>Object</code>, <code>Number</code>, and <code>Boolean</code>, all of which can be modified
1324      * or replaced.
1325      *
1326      * @param   columnClass   return the default cell renderer
1327      *                        for this columnClass
1328      * @return  the renderer for this columnClass
1329      * @see     #setDefaultRenderer
1330      * @see     #getColumnClass
1331      */
1332     public TableCellRenderer getDefaultRenderer(Class<?> columnClass) {
1333         if (columnClass == null) {
1334             return null;
1335         }
1336         else {
1337             Object renderer = defaultRenderersByColumnClass.get(columnClass);
1338             if (renderer != null) {
1339                 return (TableCellRenderer)renderer;
1340             }
1341             else {
1342                 Class c = columnClass.getSuperclass();
1343                 if (c == null && columnClass != Object.class) {
1344                     c = Object.class;
1345                 }
1346                 return getDefaultRenderer(c);
1347             }
1348         }
1349     }
1350 
1351     /**
1352      * Sets a default cell editor to be used if no editor has been set in
1353      * a <code>TableColumn</code>. If no editing is required in a table, or a
1354      * particular column in a table, uses the <code>isCellEditable</code>
1355      * method in the <code>TableModel</code> interface to ensure that this
1356      * <code>JTable</code> will not start an editor in these columns.
1357      * If editor is <code>null</code>, removes the default editor for this
1358      * column class.
1359      *
1360      * @param  columnClass  set the default cell editor for this columnClass
1361      * @param  editor   default cell editor to be used for this columnClass
1362      * @see     TableModel#isCellEditable
1363      * @see     #getDefaultEditor
1364      * @see     #setDefaultRenderer
1365      */
1366     public void setDefaultEditor(Class<?> columnClass, TableCellEditor editor) {
1367         if (editor != null) {
1368             defaultEditorsByColumnClass.put(columnClass, editor);
1369         }
1370         else {
1371             defaultEditorsByColumnClass.remove(columnClass);
1372         }
1373     }
1374 
1375     /**
1376      * Returns the editor to be used when no editor has been set in
1377      * a <code>TableColumn</code>. During the editing of cells the editor is fetched from
1378      * a <code>Hashtable</code> of entries according to the class of the cells in the column. If
1379      * there is no entry for this <code>columnClass</code> the method returns
1380      * the entry for the most specific superclass. The <code>JTable</code> installs entries
1381      * for <code>Object</code>, <code>Number</code>, and <code>Boolean</code>, all of which can be modified
1382      * or replaced.
1383      *
1384      * @param   columnClass  return the default cell editor for this columnClass
1385      * @return the default cell editor to be used for this columnClass
1386      * @see     #setDefaultEditor
1387      * @see     #getColumnClass
1388      */
1389     public TableCellEditor getDefaultEditor(Class<?> columnClass) {
1390         if (columnClass == null) {
1391             return null;
1392         }
1393         else {
1394             Object editor = defaultEditorsByColumnClass.get(columnClass);
1395             if (editor != null) {
1396                 return (TableCellEditor)editor;
1397             }
1398             else {
1399                 return getDefaultEditor(columnClass.getSuperclass());
1400             }
1401         }
1402     }
1403 
1404     /**
1405      * Turns on or off automatic drag handling. In order to enable automatic
1406      * drag handling, this property should be set to {@code true}, and the
1407      * table's {@code TransferHandler} needs to be {@code non-null}.
1408      * The default value of the {@code dragEnabled} property is {@code false}.
1409      * <p>
1410      * The job of honoring this property, and recognizing a user drag gesture,
1411      * lies with the look and feel implementation, and in particular, the table's
1412      * {@code TableUI}. When automatic drag handling is enabled, most look and
1413      * feels (including those that subclass {@code BasicLookAndFeel}) begin a
1414      * drag and drop operation whenever the user presses the mouse button over
1415      * an item (in single selection mode) or a selection (in other selection
1416      * modes) and then moves the mouse a few pixels. Setting this property to
1417      * {@code true} can therefore have a subtle effect on how selections behave.
1418      * <p>
1419      * If a look and feel is used that ignores this property, you can still
1420      * begin a drag and drop operation by calling {@code exportAsDrag} on the
1421      * table's {@code TransferHandler}.
1422      *
1423      * @param b whether or not to enable automatic drag handling
1424      * @exception HeadlessException if
1425      *            <code>b</code> is <code>true</code> and
1426      *            <code>GraphicsEnvironment.isHeadless()</code>
1427      *            returns <code>true</code>
1428      * @see java.awt.GraphicsEnvironment#isHeadless
1429      * @see #getDragEnabled
1430      * @see #setTransferHandler
1431      * @see TransferHandler
1432      * @since 1.4
1433      *
1434      * @beaninfo
1435      *  description: determines whether automatic drag handling is enabled
1436      *        bound: false
1437      */
1438     public void setDragEnabled(boolean b) {
1439         if (b && GraphicsEnvironment.isHeadless()) {
1440             throw new HeadlessException();
1441         }
1442         dragEnabled = b;
1443     }
1444 
1445     /**
1446      * Returns whether or not automatic drag handling is enabled.
1447      *
1448      * @return the value of the {@code dragEnabled} property
1449      * @see #setDragEnabled
1450      * @since 1.4
1451      */
1452     public boolean getDragEnabled() {
1453         return dragEnabled;
1454     }
1455 
1456     /**
1457      * Sets the drop mode for this component. For backward compatibility,
1458      * the default for this property is <code>DropMode.USE_SELECTION</code>.
1459      * Usage of one of the other modes is recommended, however, for an
1460      * improved user experience. <code>DropMode.ON</code>, for instance,
1461      * offers similar behavior of showing items as selected, but does so without
1462      * affecting the actual selection in the table.
1463      * <p>
1464      * <code>JTable</code> supports the following drop modes:
1465      * <ul>
1466      *    <li><code>DropMode.USE_SELECTION</code></li>
1467      *    <li><code>DropMode.ON</code></li>
1468      *    <li><code>DropMode.INSERT</code></li>
1469      *    <li><code>DropMode.INSERT_ROWS</code></li>
1470      *    <li><code>DropMode.INSERT_COLS</code></li>
1471      *    <li><code>DropMode.ON_OR_INSERT</code></li>
1472      *    <li><code>DropMode.ON_OR_INSERT_ROWS</code></li>
1473      *    <li><code>DropMode.ON_OR_INSERT_COLS</code></li>
1474      * </ul>
1475      * <p>
1476      * The drop mode is only meaningful if this component has a
1477      * <code>TransferHandler</code> that accepts drops.
1478      *
1479      * @param dropMode the drop mode to use
1480      * @throws IllegalArgumentException if the drop mode is unsupported
1481      *         or <code>null</code>
1482      * @see #getDropMode
1483      * @see #getDropLocation
1484      * @see #setTransferHandler
1485      * @see TransferHandler
1486      * @since 1.6
1487      */
1488     public final void setDropMode(DropMode dropMode) {
1489         if (dropMode != null) {
1490             switch (dropMode) {
1491                 case USE_SELECTION:
1492                 case ON:
1493                 case INSERT:
1494                 case INSERT_ROWS:
1495                 case INSERT_COLS:
1496                 case ON_OR_INSERT:
1497                 case ON_OR_INSERT_ROWS:
1498                 case ON_OR_INSERT_COLS:
1499                     this.dropMode = dropMode;
1500                     return;
1501             }
1502         }
1503 
1504         throw new IllegalArgumentException(dropMode + ": Unsupported drop mode for table");
1505     }
1506 
1507     /**
1508      * Returns the drop mode for this component.
1509      *
1510      * @return the drop mode for this component
1511      * @see #setDropMode
1512      * @since 1.6
1513      */
1514     public final DropMode getDropMode() {
1515         return dropMode;
1516     }
1517 
1518     /**
1519      * Calculates a drop location in this component, representing where a
1520      * drop at the given point should insert data.
1521      *
1522      * @param p the point to calculate a drop location for
1523      * @return the drop location, or <code>null</code>
1524      */
1525     DropLocation dropLocationForPoint(Point p) {
1526         DropLocation location = null;
1527 
1528         int row = rowAtPoint(p);
1529         int col = columnAtPoint(p);
1530         boolean outside = Boolean.TRUE == getClientProperty("Table.isFileList")
1531                           && SwingUtilities2.pointOutsidePrefSize(this, row, col, p);
1532 
1533         Rectangle rect = getCellRect(row, col, true);
1534         Section xSection, ySection;
1535         boolean between = false;
1536         boolean ltr = getComponentOrientation().isLeftToRight();
1537 
1538         switch(dropMode) {
1539             case USE_SELECTION:
1540             case ON:
1541                 if (row == -1 || col == -1 || outside) {
1542                     location = new DropLocation(p, -1, -1, false, false);
1543                 } else {
1544                     location = new DropLocation(p, row, col, false, false);
1545                 }
1546                 break;
1547             case INSERT:
1548                 if (row == -1 && col == -1) {
1549                     location = new DropLocation(p, 0, 0, true, true);
1550                     break;
1551                 }
1552 
1553                 xSection = SwingUtilities2.liesInHorizontal(rect, p, ltr, true);
1554 
1555                 if (row == -1) {
1556                     if (xSection == LEADING) {
1557                         location = new DropLocation(p, getRowCount(), col, true, true);
1558                     } else if (xSection == TRAILING) {
1559                         location = new DropLocation(p, getRowCount(), col + 1, true, true);
1560                     } else {
1561                         location = new DropLocation(p, getRowCount(), col, true, false);
1562                     }
1563                 } else if (xSection == LEADING || xSection == TRAILING) {
1564                     ySection = SwingUtilities2.liesInVertical(rect, p, true);
1565                     if (ySection == LEADING) {
1566                         between = true;
1567                     } else if (ySection == TRAILING) {
1568                         row++;
1569                         between = true;
1570                     }
1571 
1572                     location = new DropLocation(p, row,
1573                                                 xSection == TRAILING ? col + 1 : col,
1574                                                 between, true);
1575                 } else {
1576                     if (SwingUtilities2.liesInVertical(rect, p, false) == TRAILING) {
1577                         row++;
1578                     }
1579 
1580                     location = new DropLocation(p, row, col, true, false);
1581                 }
1582 
1583                 break;
1584             case INSERT_ROWS:
1585                 if (row == -1 && col == -1) {
1586                     location = new DropLocation(p, -1, -1, false, false);
1587                     break;
1588                 }
1589 
1590                 if (row == -1) {
1591                     location = new DropLocation(p, getRowCount(), col, true, false);
1592                     break;
1593                 }
1594 
1595                 if (SwingUtilities2.liesInVertical(rect, p, false) == TRAILING) {
1596                     row++;
1597                 }
1598 
1599                 location = new DropLocation(p, row, col, true, false);
1600                 break;
1601             case ON_OR_INSERT_ROWS:
1602                 if (row == -1 && col == -1) {
1603                     location = new DropLocation(p, -1, -1, false, false);
1604                     break;
1605                 }
1606 
1607                 if (row == -1) {
1608                     location = new DropLocation(p, getRowCount(), col, true, false);
1609                     break;
1610                 }
1611 
1612                 ySection = SwingUtilities2.liesInVertical(rect, p, true);
1613                 if (ySection == LEADING) {
1614                     between = true;
1615                 } else if (ySection == TRAILING) {
1616                     row++;
1617                     between = true;
1618                 }
1619 
1620                 location = new DropLocation(p, row, col, between, false);
1621                 break;
1622             case INSERT_COLS:
1623                 if (row == -1) {
1624                     location = new DropLocation(p, -1, -1, false, false);
1625                     break;
1626                 }
1627 
1628                 if (col == -1) {
1629                     location = new DropLocation(p, getColumnCount(), col, false, true);
1630                     break;
1631                 }
1632 
1633                 if (SwingUtilities2.liesInHorizontal(rect, p, ltr, false) == TRAILING) {
1634                     col++;
1635                 }
1636 
1637                 location = new DropLocation(p, row, col, false, true);
1638                 break;
1639             case ON_OR_INSERT_COLS:
1640                 if (row == -1) {
1641                     location = new DropLocation(p, -1, -1, false, false);
1642                     break;
1643                 }
1644 
1645                 if (col == -1) {
1646                     location = new DropLocation(p, row, getColumnCount(), false, true);
1647                     break;
1648                 }
1649 
1650                 xSection = SwingUtilities2.liesInHorizontal(rect, p, ltr, true);
1651                 if (xSection == LEADING) {
1652                     between = true;
1653                 } else if (xSection == TRAILING) {
1654                     col++;
1655                     between = true;
1656                 }
1657 
1658                 location = new DropLocation(p, row, col, false, between);
1659                 break;
1660             case ON_OR_INSERT:
1661                 if (row == -1 && col == -1) {
1662                     location = new DropLocation(p, 0, 0, true, true);
1663                     break;
1664                 }
1665 
1666                 xSection = SwingUtilities2.liesInHorizontal(rect, p, ltr, true);
1667 
1668                 if (row == -1) {
1669                     if (xSection == LEADING) {
1670                         location = new DropLocation(p, getRowCount(), col, true, true);
1671                     } else if (xSection == TRAILING) {
1672                         location = new DropLocation(p, getRowCount(), col + 1, true, true);
1673                     } else {
1674                         location = new DropLocation(p, getRowCount(), col, true, false);
1675                     }
1676 
1677                     break;
1678                 }
1679 
1680                 ySection = SwingUtilities2.liesInVertical(rect, p, true);
1681                 if (ySection == LEADING) {
1682                     between = true;
1683                 } else if (ySection == TRAILING) {
1684                     row++;
1685                     between = true;
1686                 }
1687 
1688                 location = new DropLocation(p, row,
1689                                             xSection == TRAILING ? col + 1 : col,
1690                                             between,
1691                                             xSection != MIDDLE);
1692 
1693                 break;
1694             default:
1695                 assert false : "Unexpected drop mode";
1696         }
1697 
1698         return location;
1699     }
1700 
1701     /**
1702      * Called to set or clear the drop location during a DnD operation.
1703      * In some cases, the component may need to use it's internal selection
1704      * temporarily to indicate the drop location. To help facilitate this,
1705      * this method returns and accepts as a parameter a state object.
1706      * This state object can be used to store, and later restore, the selection
1707      * state. Whatever this method returns will be passed back to it in
1708      * future calls, as the state parameter. If it wants the DnD system to
1709      * continue storing the same state, it must pass it back every time.
1710      * Here's how this is used:
1711      * <p>
1712      * Let's say that on the first call to this method the component decides
1713      * to save some state (because it is about to use the selection to show
1714      * a drop index). It can return a state object to the caller encapsulating
1715      * any saved selection state. On a second call, let's say the drop location
1716      * is being changed to something else. The component doesn't need to
1717      * restore anything yet, so it simply passes back the same state object
1718      * to have the DnD system continue storing it. Finally, let's say this
1719      * method is messaged with <code>null</code>. This means DnD
1720      * is finished with this component for now, meaning it should restore
1721      * state. At this point, it can use the state parameter to restore
1722      * said state, and of course return <code>null</code> since there's
1723      * no longer anything to store.
1724      *
1725      * @param location the drop location (as calculated by
1726      *        <code>dropLocationForPoint</code>) or <code>null</code>
1727      *        if there's no longer a valid drop location
1728      * @param state the state object saved earlier for this component,
1729      *        or <code>null</code>
1730      * @param forDrop whether or not the method is being called because an
1731      *        actual drop occurred
1732      * @return any saved state for this component, or <code>null</code> if none
1733      */
1734     Object setDropLocation(TransferHandler.DropLocation location,
1735                            Object state,
1736                            boolean forDrop) {
1737 
1738         Object retVal = null;
1739         DropLocation tableLocation = (DropLocation)location;
1740 
1741         if (dropMode == DropMode.USE_SELECTION) {
1742             if (tableLocation == null) {
1743                 if (!forDrop && state != null) {
1744                     clearSelection();
1745 
1746                     int[] rows = ((int[][])state)[0];
1747                     int[] cols = ((int[][])state)[1];
1748                     int[] anchleads = ((int[][])state)[2];
1749 
1750                     for (int row : rows) {
1751                         addRowSelectionInterval(row, row);
1752                     }
1753 
1754                     for (int col : cols) {
1755                         addColumnSelectionInterval(col, col);
1756                     }
1757 
1758                     SwingUtilities2.setLeadAnchorWithoutSelection(
1759                             getSelectionModel(), anchleads[1], anchleads[0]);
1760 
1761                     SwingUtilities2.setLeadAnchorWithoutSelection(
1762                             getColumnModel().getSelectionModel(),
1763                             anchleads[3], anchleads[2]);
1764                 }
1765             } else {
1766                 if (dropLocation == null) {
1767                     retVal = new int[][]{
1768                         getSelectedRows(),
1769                         getSelectedColumns(),
1770                         {getAdjustedIndex(getSelectionModel()
1771                              .getAnchorSelectionIndex(), true),
1772                          getAdjustedIndex(getSelectionModel()
1773                              .getLeadSelectionIndex(), true),
1774                          getAdjustedIndex(getColumnModel().getSelectionModel()
1775                              .getAnchorSelectionIndex(), false),
1776                          getAdjustedIndex(getColumnModel().getSelectionModel()
1777                              .getLeadSelectionIndex(), false)}};
1778                 } else {
1779                     retVal = state;
1780                 }
1781 
1782                 if (tableLocation.getRow() == -1) {
1783                     clearSelectionAndLeadAnchor();
1784                 } else {
1785                     setRowSelectionInterval(tableLocation.getRow(),
1786                                             tableLocation.getRow());
1787                     setColumnSelectionInterval(tableLocation.getColumn(),
1788                                                tableLocation.getColumn());
1789                 }
1790             }
1791         }
1792 
1793         DropLocation old = dropLocation;
1794         dropLocation = tableLocation;
1795         firePropertyChange("dropLocation", old, dropLocation);
1796 
1797         return retVal;
1798     }
1799 
1800     /**
1801      * Returns the location that this component should visually indicate
1802      * as the drop location during a DnD operation over the component,
1803      * or {@code null} if no location is to currently be shown.
1804      * <p>
1805      * This method is not meant for querying the drop location
1806      * from a {@code TransferHandler}, as the drop location is only
1807      * set after the {@code TransferHandler}'s <code>canImport</code>
1808      * has returned and has allowed for the location to be shown.
1809      * <p>
1810      * When this property changes, a property change event with
1811      * name "dropLocation" is fired by the component.
1812      *
1813      * @return the drop location
1814      * @see #setDropMode
1815      * @see TransferHandler#canImport(TransferHandler.TransferSupport)
1816      * @since 1.6
1817      */
1818     public final DropLocation getDropLocation() {
1819         return dropLocation;
1820     }
1821 
1822     /**
1823      * Specifies whether a {@code RowSorter} should be created for the
1824      * table whenever its model changes.
1825      * <p>
1826      * When {@code setAutoCreateRowSorter(true)} is invoked, a {@code
1827      * TableRowSorter} is immediately created and installed on the
1828      * table.  While the {@code autoCreateRowSorter} property remains
1829      * {@code true}, every time the model is changed, a new {@code
1830      * TableRowSorter} is created and set as the table's row sorter.
1831      *
1832      * @param autoCreateRowSorter whether or not a {@code RowSorter}
1833      *        should be automatically created
1834      * @see javax.swing.table.TableRowSorter
1835      * @beaninfo
1836      *        bound: true
1837      *    preferred: true
1838      *  description: Whether or not to turn on sorting by default.
1839      * @since 1.6
1840      */
1841     public void setAutoCreateRowSorter(boolean autoCreateRowSorter) {
1842         boolean oldValue = this.autoCreateRowSorter;
1843         this.autoCreateRowSorter = autoCreateRowSorter;
1844         if (autoCreateRowSorter) {
1845             setRowSorter(new TableRowSorter<TableModel>(getModel()));
1846         }
1847         firePropertyChange("autoCreateRowSorter", oldValue,
1848                            autoCreateRowSorter);
1849     }
1850 
1851     /**
1852      * Returns {@code true} if whenever the model changes, a new
1853      * {@code RowSorter} should be created and installed
1854      * as the table's sorter; otherwise, returns {@code false}.
1855      *
1856      * @return true if a {@code RowSorter} should be created when
1857      *         the model changes
1858      * @since 1.6
1859      */
1860     public boolean getAutoCreateRowSorter() {
1861         return autoCreateRowSorter;
1862     }
1863 
1864     /**
1865      * Specifies whether the selection should be updated after sorting.
1866      * If true, on sorting the selection is reset such that
1867      * the same rows, in terms of the model, remain selected.  The default
1868      * is true.
1869      *
1870      * @param update whether or not to update the selection on sorting
1871      * @beaninfo
1872      *        bound: true
1873      *       expert: true
1874      *  description: Whether or not to update the selection on sorting
1875      * @since 1.6
1876      */
1877     public void setUpdateSelectionOnSort(boolean update) {
1878         if (updateSelectionOnSort != update) {
1879             updateSelectionOnSort = update;
1880             firePropertyChange("updateSelectionOnSort", !update, update);
1881         }
1882     }
1883 
1884     /**
1885      * Returns true if the selection should be updated after sorting.
1886      *
1887      * @return whether to update the selection on a sort
1888      * @since 1.6
1889      */
1890     public boolean getUpdateSelectionOnSort() {
1891         return updateSelectionOnSort;
1892     }
1893 
1894     /**
1895      * Sets the <code>RowSorter</code>.  <code>RowSorter</code> is used
1896      * to provide sorting and filtering to a <code>JTable</code>.
1897      * <p>
1898      * This method clears the selection and resets any variable row heights.
1899      * <p>
1900      * This method fires a <code>PropertyChangeEvent</code> when appropriate,
1901      * with the property name <code>"rowSorter"</code>.  For
1902      * backward-compatibility, this method fires an additional event with the
1903      * property name <code>"sorter"</code>.
1904      * <p>
1905      * If the underlying model of the <code>RowSorter</code> differs from
1906      * that of this <code>JTable</code> undefined behavior will result.
1907      *
1908      * @param sorter the <code>RowSorter</code>; <code>null</code> turns
1909      *        sorting off
1910      * @see javax.swing.table.TableRowSorter
1911      * @beaninfo
1912      *        bound: true
1913      *  description: The table's RowSorter
1914      * @since 1.6
1915      */
1916     public void setRowSorter(RowSorter<? extends TableModel> sorter) {
1917         RowSorter<? extends TableModel> oldRowSorter = null;
1918         if (sortManager != null) {
1919             oldRowSorter = sortManager.sorter;
1920             sortManager.dispose();
1921             sortManager = null;
1922         }
1923         rowModel = null;
1924         clearSelectionAndLeadAnchor();
1925         if (sorter != null) {
1926             sortManager = new SortManager(sorter);
1927         }
1928         resizeAndRepaint();
1929         firePropertyChange("rowSorter", oldRowSorter, sorter);
1930         firePropertyChange("sorter", oldRowSorter, sorter);
1931     }
1932 
1933     /**
1934      * Returns the object responsible for sorting.
1935      *
1936      * @return the object responsible for sorting
1937      * @since 1.6
1938      */
1939     public RowSorter<? extends TableModel> getRowSorter() {
1940         return (sortManager != null) ? sortManager.sorter : null;
1941     }
1942 
1943 //
1944 // Selection methods
1945 //
1946     /**
1947      * Sets the table's selection mode to allow only single selections, a single
1948      * contiguous interval, or multiple intervals.
1949      * <P>
1950      * <bold>Note:</bold>
1951      * <code>JTable</code> provides all the methods for handling
1952      * column and row selection.  When setting states,
1953      * such as <code>setSelectionMode</code>, it not only
1954      * updates the mode for the row selection model but also sets similar
1955      * values in the selection model of the <code>columnModel</code>.
1956      * If you want to have the row and column selection models operating
1957      * in different modes, set them both directly.
1958      * <p>
1959      * Both the row and column selection models for <code>JTable</code>
1960      * default to using a <code>DefaultListSelectionModel</code>
1961      * so that <code>JTable</code> works the same way as the
1962      * <code>JList</code>. See the <code>setSelectionMode</code> method
1963      * in <code>JList</code> for details about the modes.
1964      *
1965      * @see JList#setSelectionMode
1966      * @beaninfo
1967      * description: The selection mode used by the row and column selection models.
1968      *        enum: SINGLE_SELECTION            ListSelectionModel.SINGLE_SELECTION
1969      *              SINGLE_INTERVAL_SELECTION   ListSelectionModel.SINGLE_INTERVAL_SELECTION
1970      *              MULTIPLE_INTERVAL_SELECTION ListSelectionModel.MULTIPLE_INTERVAL_SELECTION
1971      */
1972     public void setSelectionMode(int selectionMode) {
1973         clearSelection();
1974         getSelectionModel().setSelectionMode(selectionMode);
1975         getColumnModel().getSelectionModel().setSelectionMode(selectionMode);
1976     }
1977 
1978     /**
1979      * Sets whether the rows in this model can be selected.
1980      *
1981      * @param rowSelectionAllowed   true if this model will allow row selection
1982      * @see #getRowSelectionAllowed
1983      * @beaninfo
1984      *  bound: true
1985      *    attribute: visualUpdate true
1986      *  description: If true, an entire row is selected for each selected cell.
1987      */
1988     public void setRowSelectionAllowed(boolean rowSelectionAllowed) {
1989         boolean old = this.rowSelectionAllowed;
1990         this.rowSelectionAllowed = rowSelectionAllowed;
1991         if (old != rowSelectionAllowed) {
1992             repaint();
1993         }
1994         firePropertyChange("rowSelectionAllowed", old, rowSelectionAllowed);
1995     }
1996 
1997     /**
1998      * Returns true if rows can be selected.
1999      *
2000      * @return true if rows can be selected, otherwise false
2001      * @see #setRowSelectionAllowed
2002      */
2003     public boolean getRowSelectionAllowed() {
2004         return rowSelectionAllowed;
2005     }
2006 
2007     /**
2008      * Sets whether the columns in this model can be selected.
2009      *
2010      * @param columnSelectionAllowed   true if this model will allow column selection
2011      * @see #getColumnSelectionAllowed
2012      * @beaninfo
2013      *  bound: true
2014      *    attribute: visualUpdate true
2015      *  description: If true, an entire column is selected for each selected cell.
2016      */
2017     public void setColumnSelectionAllowed(boolean columnSelectionAllowed) {
2018         boolean old = columnModel.getColumnSelectionAllowed();
2019         columnModel.setColumnSelectionAllowed(columnSelectionAllowed);
2020         if (old != columnSelectionAllowed) {
2021             repaint();
2022         }
2023         firePropertyChange("columnSelectionAllowed", old, columnSelectionAllowed);
2024     }
2025 
2026     /**
2027      * Returns true if columns can be selected.
2028      *
2029      * @return true if columns can be selected, otherwise false
2030      * @see #setColumnSelectionAllowed
2031      */
2032     public boolean getColumnSelectionAllowed() {
2033         return columnModel.getColumnSelectionAllowed();
2034     }
2035 
2036     /**
2037      * Sets whether this table allows both a column selection and a
2038      * row selection to exist simultaneously. When set,
2039      * the table treats the intersection of the row and column selection
2040      * models as the selected cells. Override <code>isCellSelected</code> to
2041      * change this default behavior. This method is equivalent to setting
2042      * both the <code>rowSelectionAllowed</code> property and
2043      * <code>columnSelectionAllowed</code> property of the
2044      * <code>columnModel</code> to the supplied value.
2045      *
2046      * @param  cellSelectionEnabled     true if simultaneous row and column
2047      *                                  selection is allowed
2048      * @see #getCellSelectionEnabled
2049      * @see #isCellSelected
2050      * @beaninfo
2051      *  bound: true
2052      *    attribute: visualUpdate true
2053      *  description: Select a rectangular region of cells rather than
2054      *               rows or columns.
2055      */
2056     public void setCellSelectionEnabled(boolean cellSelectionEnabled) {
2057         setRowSelectionAllowed(cellSelectionEnabled);
2058         setColumnSelectionAllowed(cellSelectionEnabled);
2059         boolean old = this.cellSelectionEnabled;
2060         this.cellSelectionEnabled = cellSelectionEnabled;
2061         firePropertyChange("cellSelectionEnabled", old, cellSelectionEnabled);
2062     }
2063 
2064     /**
2065      * Returns true if both row and column selection models are enabled.
2066      * Equivalent to <code>getRowSelectionAllowed() &&
2067      * getColumnSelectionAllowed()</code>.
2068      *
2069      * @return true if both row and column selection models are enabled
2070      *
2071      * @see #setCellSelectionEnabled
2072      */
2073     public boolean getCellSelectionEnabled() {
2074         return getRowSelectionAllowed() && getColumnSelectionAllowed();
2075     }
2076 
2077     /**
2078      *  Selects all rows, columns, and cells in the table.
2079      */
2080     public void selectAll() {
2081         // If I'm currently editing, then I should stop editing
2082         if (isEditing()) {
2083             removeEditor();
2084         }
2085         if (getRowCount() > 0 && getColumnCount() > 0) {
2086             int oldLead;
2087             int oldAnchor;
2088             ListSelectionModel selModel;
2089 
2090             selModel = selectionModel;
2091             selModel.setValueIsAdjusting(true);
2092             oldLead = getAdjustedIndex(selModel.getLeadSelectionIndex(), true);
2093             oldAnchor = getAdjustedIndex(selModel.getAnchorSelectionIndex(), true);
2094 
2095             setRowSelectionInterval(0, getRowCount()-1);
2096 
2097             // this is done to restore the anchor and lead
2098             SwingUtilities2.setLeadAnchorWithoutSelection(selModel, oldLead, oldAnchor);
2099 
2100             selModel.setValueIsAdjusting(false);
2101 
2102             selModel = columnModel.getSelectionModel();
2103             selModel.setValueIsAdjusting(true);
2104             oldLead = getAdjustedIndex(selModel.getLeadSelectionIndex(), false);
2105             oldAnchor = getAdjustedIndex(selModel.getAnchorSelectionIndex(), false);
2106 
2107             setColumnSelectionInterval(0, getColumnCount()-1);
2108 
2109             // this is done to restore the anchor and lead
2110             SwingUtilities2.setLeadAnchorWithoutSelection(selModel, oldLead, oldAnchor);
2111 
2112             selModel.setValueIsAdjusting(false);
2113         }
2114     }
2115 
2116     /**
2117      * Deselects all selected columns and rows.
2118      */
2119     public void clearSelection() {
2120         selectionModel.clearSelection();
2121         columnModel.getSelectionModel().clearSelection();
2122     }
2123 
2124     private void clearSelectionAndLeadAnchor() {
2125         selectionModel.setValueIsAdjusting(true);
2126         columnModel.getSelectionModel().setValueIsAdjusting(true);
2127 
2128         clearSelection();
2129 
2130         selectionModel.setAnchorSelectionIndex(-1);
2131         selectionModel.setLeadSelectionIndex(-1);
2132         columnModel.getSelectionModel().setAnchorSelectionIndex(-1);
2133         columnModel.getSelectionModel().setLeadSelectionIndex(-1);
2134 
2135         selectionModel.setValueIsAdjusting(false);
2136         columnModel.getSelectionModel().setValueIsAdjusting(false);
2137     }
2138 
2139     private int getAdjustedIndex(int index, boolean row) {
2140         int compare = row ? getRowCount() : getColumnCount();
2141         return index < compare ? index : -1;
2142     }
2143 
2144     private int boundRow(int row) throws IllegalArgumentException {
2145         if (row < 0 || row >= getRowCount()) {
2146             throw new IllegalArgumentException("Row index out of range");
2147         }
2148         return row;
2149     }
2150 
2151     private int boundColumn(int col) {
2152         if (col< 0 || col >= getColumnCount()) {
2153             throw new IllegalArgumentException("Column index out of range");
2154         }
2155         return col;
2156     }
2157 
2158     /**
2159      * Selects the rows from <code>index0</code> to <code>index1</code>,
2160      * inclusive.
2161      *
2162      * @exception IllegalArgumentException      if <code>index0</code> or
2163      *                                          <code>index1</code> lie outside
2164      *                                          [0, <code>getRowCount()</code>-1]
2165      * @param   index0 one end of the interval
2166      * @param   index1 the other end of the interval
2167      */
2168     public void setRowSelectionInterval(int index0, int index1) {
2169         selectionModel.setSelectionInterval(boundRow(index0), boundRow(index1));
2170     }
2171 
2172     /**
2173      * Selects the columns from <code>index0</code> to <code>index1</code>,
2174      * inclusive.
2175      *
2176      * @exception IllegalArgumentException      if <code>index0</code> or
2177      *                                          <code>index1</code> lie outside
2178      *                                          [0, <code>getColumnCount()</code>-1]
2179      * @param   index0 one end of the interval
2180      * @param   index1 the other end of the interval
2181      */
2182     public void setColumnSelectionInterval(int index0, int index1) {
2183         columnModel.getSelectionModel().setSelectionInterval(boundColumn(index0), boundColumn(index1));
2184     }
2185 
2186     /**
2187      * Adds the rows from <code>index0</code> to <code>index1</code>, inclusive, to
2188      * the current selection.
2189      *
2190      * @exception IllegalArgumentException      if <code>index0</code> or <code>index1</code>
2191      *                                          lie outside [0, <code>getRowCount()</code>-1]
2192      * @param   index0 one end of the interval
2193      * @param   index1 the other end of the interval
2194      */
2195     public void addRowSelectionInterval(int index0, int index1) {
2196         selectionModel.addSelectionInterval(boundRow(index0), boundRow(index1));
2197     }
2198 
2199     /**
2200      * Adds the columns from <code>index0</code> to <code>index1</code>,
2201      * inclusive, to the current selection.
2202      *
2203      * @exception IllegalArgumentException      if <code>index0</code> or
2204      *                                          <code>index1</code> lie outside
2205      *                                          [0, <code>getColumnCount()</code>-1]
2206      * @param   index0 one end of the interval
2207      * @param   index1 the other end of the interval
2208      */
2209     public void addColumnSelectionInterval(int index0, int index1) {
2210         columnModel.getSelectionModel().addSelectionInterval(boundColumn(index0), boundColumn(index1));
2211     }
2212 
2213     /**
2214      * Deselects the rows from <code>index0</code> to <code>index1</code>, inclusive.
2215      *
2216      * @exception IllegalArgumentException      if <code>index0</code> or
2217      *                                          <code>index1</code> lie outside
2218      *                                          [0, <code>getRowCount()</code>-1]
2219      * @param   index0 one end of the interval
2220      * @param   index1 the other end of the interval
2221      */
2222     public void removeRowSelectionInterval(int index0, int index1) {
2223         selectionModel.removeSelectionInterval(boundRow(index0), boundRow(index1));
2224     }
2225 
2226     /**
2227      * Deselects the columns from <code>index0</code> to <code>index1</code>, inclusive.
2228      *
2229      * @exception IllegalArgumentException      if <code>index0</code> or
2230      *                                          <code>index1</code> lie outside
2231      *                                          [0, <code>getColumnCount()</code>-1]
2232      * @param   index0 one end of the interval
2233      * @param   index1 the other end of the interval
2234      */
2235     public void removeColumnSelectionInterval(int index0, int index1) {
2236         columnModel.getSelectionModel().removeSelectionInterval(boundColumn(index0), boundColumn(index1));
2237     }
2238 
2239     /**
2240      * Returns the index of the first selected row, -1 if no row is selected.
2241      * @return the index of the first selected row
2242      */
2243     public int getSelectedRow() {
2244         return selectionModel.getMinSelectionIndex();
2245     }
2246 
2247     /**
2248      * Returns the index of the first selected column,
2249      * -1 if no column is selected.
2250      * @return the index of the first selected column
2251      */
2252     public int getSelectedColumn() {
2253         return columnModel.getSelectionModel().getMinSelectionIndex();
2254     }
2255 
2256     /**
2257      * Returns the indices of all selected rows.
2258      *
2259      * @return an array of integers containing the indices of all selected rows,
2260      *         or an empty array if no row is selected
2261      * @see #getSelectedRow
2262      */
2263     public int[] getSelectedRows() {
2264         int iMin = selectionModel.getMinSelectionIndex();
2265         int iMax = selectionModel.getMaxSelectionIndex();
2266 
2267         if ((iMin == -1) || (iMax == -1)) {
2268             return new int[0];
2269         }
2270 
2271         int[] rvTmp = new int[1+ (iMax - iMin)];
2272         int n = 0;
2273         for(int i = iMin; i <= iMax; i++) {
2274             if (selectionModel.isSelectedIndex(i)) {
2275                 rvTmp[n++] = i;
2276             }
2277         }
2278         int[] rv = new int[n];
2279         System.arraycopy(rvTmp, 0, rv, 0, n);
2280         return rv;
2281     }
2282 
2283     /**
2284      * Returns the indices of all selected columns.
2285      *
2286      * @return an array of integers containing the indices of all selected columns,
2287      *         or an empty array if no column is selected
2288      * @see #getSelectedColumn
2289      */
2290     public int[] getSelectedColumns() {
2291         return columnModel.getSelectedColumns();
2292     }
2293 
2294     /**
2295      * Returns the number of selected rows.
2296      *
2297      * @return the number of selected rows, 0 if no rows are selected
2298      */
2299     public int getSelectedRowCount() {
2300         int iMin = selectionModel.getMinSelectionIndex();
2301         int iMax = selectionModel.getMaxSelectionIndex();
2302         int count = 0;
2303 
2304         for(int i = iMin; i <= iMax; i++) {
2305             if (selectionModel.isSelectedIndex(i)) {
2306                 count++;
2307             }
2308         }
2309         return count;
2310     }
2311 
2312     /**
2313      * Returns the number of selected columns.
2314      *
2315      * @return the number of selected columns, 0 if no columns are selected
2316      */
2317     public int getSelectedColumnCount() {
2318         return columnModel.getSelectedColumnCount();
2319     }
2320 
2321     /**
2322      * Returns true if the specified index is in the valid range of rows,
2323      * and the row at that index is selected.
2324      *
2325      * @return true if <code>row</code> is a valid index and the row at
2326      *              that index is selected (where 0 is the first row)
2327      */
2328     public boolean isRowSelected(int row) {
2329         return selectionModel.isSelectedIndex(row);
2330     }
2331 
2332     /**
2333      * Returns true if the specified index is in the valid range of columns,
2334      * and the column at that index is selected.
2335      *
2336      * @param   column   the column in the column model
2337      * @return true if <code>column</code> is a valid index and the column at
2338      *              that index is selected (where 0 is the first column)
2339      */
2340     public boolean isColumnSelected(int column) {
2341         return columnModel.getSelectionModel().isSelectedIndex(column);
2342     }
2343 
2344     /**
2345      * Returns true if the specified indices are in the valid range of rows
2346      * and columns and the cell at the specified position is selected.
2347      * @param row   the row being queried
2348      * @param column  the column being queried
2349      *
2350      * @return true if <code>row</code> and <code>column</code> are valid indices
2351      *              and the cell at index <code>(row, column)</code> is selected,
2352      *              where the first row and first column are at index 0
2353      */
2354     public boolean isCellSelected(int row, int column) {
2355         if (!getRowSelectionAllowed() && !getColumnSelectionAllowed()) {
2356             return false;
2357         }
2358         return (!getRowSelectionAllowed() || isRowSelected(row)) &&
2359                (!getColumnSelectionAllowed() || isColumnSelected(column));
2360     }
2361 
2362     private void changeSelectionModel(ListSelectionModel sm, int index,
2363                                       boolean toggle, boolean extend, boolean selected,
2364                                       int anchor, boolean anchorSelected) {
2365         if (extend) {
2366             if (toggle) {
2367                 if (anchorSelected) {
2368                     sm.addSelectionInterval(anchor, index);
2369                 } else {
2370                     sm.removeSelectionInterval(anchor, index);
2371                     // this is a Windows-only behavior that we want for file lists
2372                     if (Boolean.TRUE == getClientProperty("Table.isFileList")) {
2373                         sm.addSelectionInterval(index, index);
2374                         sm.setAnchorSelectionIndex(anchor);
2375                     }
2376                 }
2377             }
2378             else {
2379                 sm.setSelectionInterval(anchor, index);
2380             }
2381         }
2382         else {
2383             if (toggle) {
2384                 if (selected) {
2385                     sm.removeSelectionInterval(index, index);
2386                 }
2387                 else {
2388                     sm.addSelectionInterval(index, index);
2389                 }
2390             }
2391             else {
2392                 sm.setSelectionInterval(index, index);
2393             }
2394         }
2395     }
2396 
2397     /**
2398      * Updates the selection models of the table, depending on the state of the
2399      * two flags: <code>toggle</code> and <code>extend</code>. Most changes
2400      * to the selection that are the result of keyboard or mouse events received
2401      * by the UI are channeled through this method so that the behavior may be
2402      * overridden by a subclass. Some UIs may need more functionality than
2403      * this method provides, such as when manipulating the lead for discontiguous
2404      * selection, and may not call into this method for some selection changes.
2405      * <p>
2406      * This implementation uses the following conventions:
2407      * <ul>
2408      * <li> <code>toggle</code>: <em>false</em>, <code>extend</code>: <em>false</em>.
2409      *      Clear the previous selection and ensure the new cell is selected.
2410      * <li> <code>toggle</code>: <em>false</em>, <code>extend</code>: <em>true</em>.
2411      *      Extend the previous selection from the anchor to the specified cell,
2412      *      clearing all other selections.
2413      * <li> <code>toggle</code>: <em>true</em>, <code>extend</code>: <em>false</em>.
2414      *      If the specified cell is selected, deselect it. If it is not selected, select it.
2415      * <li> <code>toggle</code>: <em>true</em>, <code>extend</code>: <em>true</em>.
2416      *      Apply the selection state of the anchor to all cells between it and the
2417      *      specified cell.
2418      * </ul>
2419      * @param  rowIndex   affects the selection at <code>row</code>
2420      * @param  columnIndex  affects the selection at <code>column</code>
2421      * @param  toggle  see description above
2422      * @param  extend  if true, extend the current selection
2423      *
2424      * @since 1.3
2425      */
2426     public void changeSelection(int rowIndex, int columnIndex, boolean toggle, boolean extend) {
2427         ListSelectionModel rsm = getSelectionModel();
2428         ListSelectionModel csm = getColumnModel().getSelectionModel();
2429 
2430         int anchorRow = getAdjustedIndex(rsm.getAnchorSelectionIndex(), true);
2431         int anchorCol = getAdjustedIndex(csm.getAnchorSelectionIndex(), false);
2432 
2433         boolean anchorSelected = true;
2434 
2435         if (anchorRow == -1) {
2436             if (getRowCount() > 0) {
2437                 anchorRow = 0;
2438             }
2439             anchorSelected = false;
2440         }
2441 
2442         if (anchorCol == -1) {
2443             if (getColumnCount() > 0) {
2444                 anchorCol = 0;
2445             }
2446             anchorSelected = false;
2447         }
2448 
2449         // Check the selection here rather than in each selection model.
2450         // This is significant in cell selection mode if we are supposed
2451         // to be toggling the selection. In this case it is better to
2452         // ensure that the cell's selection state will indeed be changed.
2453         // If this were done in the code for the selection model it
2454         // might leave a cell in selection state if the row was
2455         // selected but the column was not - as it would toggle them both.
2456         boolean selected = isCellSelected(rowIndex, columnIndex);
2457         anchorSelected = anchorSelected && isCellSelected(anchorRow, anchorCol);
2458 
2459         changeSelectionModel(csm, columnIndex, toggle, extend, selected,
2460                              anchorCol, anchorSelected);
2461         changeSelectionModel(rsm, rowIndex, toggle, extend, selected,
2462                              anchorRow, anchorSelected);
2463 
2464         // Scroll after changing the selection as blit scrolling is immediate,
2465         // so that if we cause the repaint after the scroll we end up painting
2466         // everything!
2467         if (getAutoscrolls()) {
2468             Rectangle cellRect = getCellRect(rowIndex, columnIndex, false);
2469             if (cellRect != null) {
2470                 scrollRectToVisible(cellRect);
2471             }
2472         }
2473     }
2474 
2475     /**
2476      * Returns the foreground color for selected cells.
2477      *
2478      * @return the <code>Color</code> object for the foreground property
2479      * @see #setSelectionForeground
2480      * @see #setSelectionBackground
2481      */
2482     public Color getSelectionForeground() {
2483         return selectionForeground;
2484     }
2485 
2486     /**
2487      * Sets the foreground color for selected cells.  Cell renderers
2488      * can use this color to render text and graphics for selected
2489      * cells.
2490      * <p>
2491      * The default value of this property is defined by the look
2492      * and feel implementation.
2493      * <p>
2494      * This is a <a href="http://java.sun.com/docs/books/tutorial/javabeans/properties/bound.html">JavaBeans</a> bound property.
2495      *
2496      * @param selectionForeground  the <code>Color</code> to use in the foreground
2497      *                             for selected list items
2498      * @see #getSelectionForeground
2499      * @see #setSelectionBackground
2500      * @see #setForeground
2501      * @see #setBackground
2502      * @see #setFont
2503      * @beaninfo
2504      *       bound: true
2505      * description: A default foreground color for selected cells.
2506      */
2507     public void setSelectionForeground(Color selectionForeground) {
2508         Color old = this.selectionForeground;
2509         this.selectionForeground = selectionForeground;
2510         firePropertyChange("selectionForeground", old, selectionForeground);
2511         repaint();
2512     }
2513 
2514     /**
2515      * Returns the background color for selected cells.
2516      *
2517      * @return the <code>Color</code> used for the background of selected list items
2518      * @see #setSelectionBackground
2519      * @see #setSelectionForeground
2520      */
2521     public Color getSelectionBackground() {
2522         return selectionBackground;
2523     }
2524 
2525     /**
2526      * Sets the background color for selected cells.  Cell renderers
2527      * can use this color to the fill selected cells.
2528      * <p>
2529      * The default value of this property is defined by the look
2530      * and feel implementation.
2531      * <p>
2532      * This is a <a href="http://java.sun.com/docs/books/tutorial/javabeans/properties/bound.html">JavaBeans</a> bound property.
2533      *
2534      * @param selectionBackground  the <code>Color</code> to use for the background
2535      *                             of selected cells
2536      * @see #getSelectionBackground
2537      * @see #setSelectionForeground
2538      * @see #setForeground
2539      * @see #setBackground
2540      * @see #setFont
2541      * @beaninfo
2542      *       bound: true
2543      * description: A default background color for selected cells.
2544      */
2545     public void setSelectionBackground(Color selectionBackground) {
2546         Color old = this.selectionBackground;
2547         this.selectionBackground = selectionBackground;
2548         firePropertyChange("selectionBackground", old, selectionBackground);
2549         repaint();
2550     }
2551 
2552     /**
2553      * Returns the <code>TableColumn</code> object for the column in the table
2554      * whose identifier is equal to <code>identifier</code>, when compared using
2555      * <code>equals</code>.
2556      *
2557      * @return  the <code>TableColumn</code> object that matches the identifier
2558      * @exception IllegalArgumentException      if <code>identifier</code> is <code>null</code> or no <code>TableColumn</code> has this identifier
2559      *
2560      * @param   identifier                      the identifier object
2561      */
2562     public TableColumn getColumn(Object identifier) {
2563         TableColumnModel cm = getColumnModel();
2564         int columnIndex = cm.getColumnIndex(identifier);
2565         return cm.getColumn(columnIndex);
2566     }
2567 
2568 //
2569 // Informally implement the TableModel interface.
2570 //
2571 
2572     /**
2573      * Maps the index of the column in the view at
2574      * <code>viewColumnIndex</code> to the index of the column
2575      * in the table model.  Returns the index of the corresponding
2576      * column in the model.  If <code>viewColumnIndex</code>
2577      * is less than zero, returns <code>viewColumnIndex</code>.
2578      *
2579      * @param   viewColumnIndex     the index of the column in the view
2580      * @return  the index of the corresponding column in the model
2581      *
2582      * @see #convertColumnIndexToView
2583      */
2584     public int convertColumnIndexToModel(int viewColumnIndex) {
2585         return SwingUtilities2.convertColumnIndexToModel(
2586                 getColumnModel(), viewColumnIndex);
2587     }
2588 
2589     /**
2590      * Maps the index of the column in the table model at
2591      * <code>modelColumnIndex</code> to the index of the column
2592      * in the view.  Returns the index of the
2593      * corresponding column in the view; returns -1 if this column is not
2594      * being displayed.  If <code>modelColumnIndex</code> is less than zero,
2595      * returns <code>modelColumnIndex</code>.
2596      *
2597      * @param   modelColumnIndex     the index of the column in the model
2598      * @return   the index of the corresponding column in the view
2599      *
2600      * @see #convertColumnIndexToModel
2601      */
2602     public int convertColumnIndexToView(int modelColumnIndex) {
2603         return SwingUtilities2.convertColumnIndexToView(
2604                 getColumnModel(), modelColumnIndex);
2605     }
2606 
2607     /**
2608      * Maps the index of the row in terms of the
2609      * <code>TableModel</code> to the view.  If the contents of the
2610      * model are not sorted the model and view indices are the same.
2611      *
2612      * @param modelRowIndex the index of the row in terms of the model
2613      * @return the index of the corresponding row in the view, or -1 if
2614      *         the row isn't visible
2615      * @throws IndexOutOfBoundsException if sorting is enabled and passed an
2616      *         index outside the number of rows of the <code>TableModel</code>
2617      * @see javax.swing.table.TableRowSorter
2618      * @since 1.6
2619      */
2620     public int convertRowIndexToView(int modelRowIndex) {
2621         RowSorter sorter = getRowSorter();
2622         if (sorter != null) {
2623             return sorter.convertRowIndexToView(modelRowIndex);
2624         }
2625         return modelRowIndex;
2626     }
2627 
2628     /**
2629      * Maps the index of the row in terms of the view to the
2630      * underlying <code>TableModel</code>.  If the contents of the
2631      * model are not sorted the model and view indices are the same.
2632      *
2633      * @param viewRowIndex the index of the row in the view
2634      * @return the index of the corresponding row in the model
2635      * @throws IndexOutOfBoundsException if sorting is enabled and passed an
2636      *         index outside the range of the <code>JTable</code> as
2637      *         determined by the method <code>getRowCount</code>
2638      * @see javax.swing.table.TableRowSorter
2639      * @see #getRowCount
2640      * @since 1.6
2641      */
2642     public int convertRowIndexToModel(int viewRowIndex) {
2643         RowSorter sorter = getRowSorter();
2644         if (sorter != null) {
2645             return sorter.convertRowIndexToModel(viewRowIndex);
2646         }
2647         return viewRowIndex;
2648     }
2649 
2650     /**
2651      * Returns the number of rows that can be shown in the
2652      * <code>JTable</code>, given unlimited space.  If a
2653      * <code>RowSorter</code> with a filter has been specified, the
2654      * number of rows returned may differ from that of the underlying
2655      * <code>TableModel</code>.
2656      *
2657      * @return the number of rows shown in the <code>JTable</code>
2658      * @see #getColumnCount
2659      */
2660     public int getRowCount() {
2661         RowSorter sorter = getRowSorter();
2662         if (sorter != null) {
2663             return sorter.getViewRowCount();
2664         }
2665         return getModel().getRowCount();
2666     }
2667 
2668     /**
2669      * Returns the number of columns in the column model. Note that this may
2670      * be different from the number of columns in the table model.
2671      *
2672      * @return  the number of columns in the table
2673      * @see #getRowCount
2674      * @see #removeColumn
2675      */
2676     public int getColumnCount() {
2677         return getColumnModel().getColumnCount();
2678     }
2679 
2680     /**
2681      * Returns the name of the column appearing in the view at
2682      * column position <code>column</code>.
2683      *
2684      * @param  column    the column in the view being queried
2685      * @return the name of the column at position <code>column</code>
2686                         in the view where the first column is column 0
2687      */
2688     public String getColumnName(int column) {
2689         return getModel().getColumnName(convertColumnIndexToModel(column));
2690     }
2691 
2692     /**
2693      * Returns the type of the column appearing in the view at
2694      * column position <code>column</code>.
2695      *
2696      * @param   column   the column in the view being queried
2697      * @return the type of the column at position <code>column</code>
2698      *          in the view where the first column is column 0
2699      */
2700     public Class<?> getColumnClass(int column) {
2701         return getModel().getColumnClass(convertColumnIndexToModel(column));
2702     }
2703 
2704     /**
2705      * Returns the cell value at <code>row</code> and <code>column</code>.
2706      * <p>
2707      * <b>Note</b>: The column is specified in the table view's display
2708      *              order, and not in the <code>TableModel</code>'s column
2709      *              order.  This is an important distinction because as the
2710      *              user rearranges the columns in the table,
2711      *              the column at a given index in the view will change.
2712      *              Meanwhile the user's actions never affect the model's
2713      *              column ordering.
2714      *
2715      * @param   row             the row whose value is to be queried
2716      * @param   column          the column whose value is to be queried
2717      * @return  the Object at the specified cell
2718      */
2719     public Object getValueAt(int row, int column) {
2720         return getModel().getValueAt(convertRowIndexToModel(row),
2721                                      convertColumnIndexToModel(column));
2722     }
2723 
2724     /**
2725      * Sets the value for the cell in the table model at <code>row</code>
2726      * and <code>column</code>.
2727      * <p>
2728      * <b>Note</b>: The column is specified in the table view's display
2729      *              order, and not in the <code>TableModel</code>'s column
2730      *              order.  This is an important distinction because as the
2731      *              user rearranges the columns in the table,
2732      *              the column at a given index in the view will change.
2733      *              Meanwhile the user's actions never affect the model's
2734      *              column ordering.
2735      *
2736      * <code>aValue</code> is the new value.
2737      *
2738      * @param   aValue          the new value
2739      * @param   row             the row of the cell to be changed
2740      * @param   column          the column of the cell to be changed
2741      * @see #getValueAt
2742      */
2743     public void setValueAt(Object aValue, int row, int column) {
2744         getModel().setValueAt(aValue, convertRowIndexToModel(row),
2745                               convertColumnIndexToModel(column));
2746     }
2747 
2748     /**
2749      * Returns true if the cell at <code>row</code> and <code>column</code>
2750      * is editable.  Otherwise, invoking <code>setValueAt</code> on the cell
2751      * will have no effect.
2752      * <p>
2753      * <b>Note</b>: The column is specified in the table view's display
2754      *              order, and not in the <code>TableModel</code>'s column
2755      *              order.  This is an important distinction because as the
2756      *              user rearranges the columns in the table,
2757      *              the column at a given index in the view will change.
2758      *              Meanwhile the user's actions never affect the model's
2759      *              column ordering.
2760      *
2761      *
2762      * @param   row      the row whose value is to be queried
2763      * @param   column   the column whose value is to be queried
2764      * @return  true if the cell is editable
2765      * @see #setValueAt
2766      */
2767     public boolean isCellEditable(int row, int column) {
2768         return getModel().isCellEditable(convertRowIndexToModel(row),
2769                                          convertColumnIndexToModel(column));
2770     }
2771 //
2772 // Adding and removing columns in the view
2773 //
2774 
2775     /**
2776      *  Appends <code>aColumn</code> to the end of the array of columns held by
2777      *  this <code>JTable</code>'s column model.
2778      *  If the column name of <code>aColumn</code> is <code>null</code>,
2779      *  sets the column name of <code>aColumn</code> to the name
2780      *  returned by <code>getModel().getColumnName()</code>.
2781      *  <p>
2782      *  To add a column to this <code>JTable</code> to display the
2783      *  <code>modelColumn</code>'th column of data in the model with a
2784      *  given <code>width</code>, <code>cellRenderer</code>,
2785      *  and <code>cellEditor</code> you can use:
2786      *  <pre>
2787      *
2788      *      addColumn(new TableColumn(modelColumn, width, cellRenderer, cellEditor));
2789      *
2790      *  </pre>
2791      *  [Any of the <code>TableColumn</code> constructors can be used
2792      *  instead of this one.]
2793      *  The model column number is stored inside the <code>TableColumn</code>
2794      *  and is used during rendering and editing to locate the appropriates
2795      *  data values in the model. The model column number does not change
2796      *  when columns are reordered in the view.
2797      *
2798      *  @param  aColumn         the <code>TableColumn</code> to be added
2799      *  @see    #removeColumn
2800      */
2801     public void addColumn(TableColumn aColumn) {
2802         if (aColumn.getHeaderValue() == null) {
2803             int modelColumn = aColumn.getModelIndex();
2804             String columnName = getModel().getColumnName(modelColumn);
2805             aColumn.setHeaderValue(columnName);
2806         }
2807         getColumnModel().addColumn(aColumn);
2808     }
2809 
2810     /**
2811      *  Removes <code>aColumn</code> from this <code>JTable</code>'s
2812      *  array of columns.  Note: this method does not remove the column
2813      *  of data from the model; it just removes the <code>TableColumn</code>
2814      *  that was responsible for displaying it.
2815      *
2816      *  @param  aColumn         the <code>TableColumn</code> to be removed
2817      *  @see    #addColumn
2818      */
2819     public void removeColumn(TableColumn aColumn) {
2820         getColumnModel().removeColumn(aColumn);
2821     }
2822 
2823     /**
2824      * Moves the column <code>column</code> to the position currently
2825      * occupied by the column <code>targetColumn</code> in the view.
2826      * The old column at <code>targetColumn</code> is
2827      * shifted left or right to make room.
2828      *
2829      * @param   column                  the index of column to be moved
2830      * @param   targetColumn            the new index of the column
2831      */
2832     public void moveColumn(int column, int targetColumn) {
2833         getColumnModel().moveColumn(column, targetColumn);
2834     }
2835 
2836 //
2837 // Cover methods for various models and helper methods
2838 //
2839 
2840     /**
2841      * Returns the index of the column that <code>point</code> lies in,
2842      * or -1 if the result is not in the range
2843      * [0, <code>getColumnCount()</code>-1].
2844      *
2845      * @param   point   the location of interest
2846      * @return  the index of the column that <code>point</code> lies in,
2847      *          or -1 if the result is not in the range
2848      *          [0, <code>getColumnCount()</code>-1]
2849      * @see     #rowAtPoint
2850      */
2851     public int columnAtPoint(Point point) {
2852         int x = point.x;
2853         if( !getComponentOrientation().isLeftToRight() ) {
2854             x = getWidth() - x - 1;
2855         }
2856         return getColumnModel().getColumnIndexAtX(x);
2857     }
2858 
2859     /**
2860      * Returns the index of the row that <code>point</code> lies in,
2861      * or -1 if the result is not in the range
2862      * [0, <code>getRowCount()</code>-1].
2863      *
2864      * @param   point   the location of interest
2865      * @return  the index of the row that <code>point</code> lies in,
2866      *          or -1 if the result is not in the range
2867      *          [0, <code>getRowCount()</code>-1]
2868      * @see     #columnAtPoint
2869      */
2870     public int rowAtPoint(Point point) {
2871         int y = point.y;
2872         int result = (rowModel == null) ?  y/getRowHeight() : rowModel.getIndex(y);
2873         if (result < 0) {
2874             return -1;
2875         }
2876         else if (result >= getRowCount()) {
2877             return -1;
2878         }
2879         else {
2880             return result;
2881         }
2882     }
2883 
2884     /**
2885      * Returns a rectangle for the cell that lies at the intersection of
2886      * <code>row</code> and <code>column</code>.
2887      * If <code>includeSpacing</code> is true then the value returned
2888      * has the full height and width of the row and column
2889      * specified. If it is false, the returned rectangle is inset by the
2890      * intercell spacing to return the true bounds of the rendering or
2891      * editing component as it will be set during rendering.
2892      * <p>
2893      * If the column index is valid but the row index is less
2894      * than zero the method returns a rectangle with the
2895      * <code>y</code> and <code>height</code> values set appropriately
2896      * and the <code>x</code> and <code>width</code> values both set
2897      * to zero. In general, when either the row or column indices indicate a
2898      * cell outside the appropriate range, the method returns a rectangle
2899      * depicting the closest edge of the closest cell that is within
2900      * the table's range. When both row and column indices are out
2901      * of range the returned rectangle covers the closest
2902      * point of the closest cell.
2903      * <p>
2904      * In all cases, calculations that use this method to calculate
2905      * results along one axis will not fail because of anomalies in
2906      * calculations along the other axis. When the cell is not valid
2907      * the <code>includeSpacing</code> parameter is ignored.
2908      *
2909      * @param   row                   the row index where the desired cell
2910      *                                is located
2911      * @param   column                the column index where the desired cell
2912      *                                is located in the display; this is not
2913      *                                necessarily the same as the column index
2914      *                                in the data model for the table; the
2915      *                                {@link #convertColumnIndexToView(int)}
2916      *                                method may be used to convert a data
2917      *                                model column index to a display
2918      *                                column index
2919      * @param   includeSpacing        if false, return the true cell bounds -
2920      *                                computed by subtracting the intercell
2921      *                                spacing from the height and widths of
2922      *                                the column and row models
2923      *
2924      * @return  the rectangle containing the cell at location
2925      *          <code>row</code>,<code>column</code>
2926      * @see #getIntercellSpacing
2927      */
2928     public Rectangle getCellRect(int row, int column, boolean includeSpacing) {
2929         Rectangle r = new Rectangle();
2930         boolean valid = true;
2931         if (row < 0) {
2932             // y = height = 0;
2933             valid = false;
2934         }
2935         else if (row >= getRowCount()) {
2936             r.y = getHeight();
2937             valid = false;
2938         }
2939         else {
2940             r.height = getRowHeight(row);
2941             r.y = (rowModel == null) ? row * r.height : rowModel.getPosition(row);
2942         }
2943 
2944         if (column < 0) {
2945             if( !getComponentOrientation().isLeftToRight() ) {
2946                 r.x = getWidth();
2947             }
2948             // otherwise, x = width = 0;
2949             valid = false;
2950         }
2951         else if (column >= getColumnCount()) {
2952             if( getComponentOrientation().isLeftToRight() ) {
2953                 r.x = getWidth();
2954             }
2955             // otherwise, x = width = 0;
2956             valid = false;
2957         }
2958         else {
2959             TableColumnModel cm = getColumnModel();
2960             if( getComponentOrientation().isLeftToRight() ) {
2961                 for(int i = 0; i < column; i++) {
2962                     r.x += cm.getColumn(i).getWidth();
2963                 }
2964             } else {
2965                 for(int i = cm.getColumnCount()-1; i > column; i--) {
2966                     r.x += cm.getColumn(i).getWidth();
2967                 }
2968             }
2969             r.width = cm.getColumn(column).getWidth();
2970         }
2971 
2972         if (valid && !includeSpacing) {
2973             // Bound the margins by their associated dimensions to prevent
2974             // returning bounds with negative dimensions.
2975             int rm = Math.min(getRowMargin(), r.height);
2976             int cm = Math.min(getColumnModel().getColumnMargin(), r.width);
2977             // This is not the same as grow(), it rounds differently.
2978             r.setBounds(r.x + cm/2, r.y + rm/2, r.width - cm, r.height - rm);
2979         }
2980         return r;
2981     }
2982 
2983     private int viewIndexForColumn(TableColumn aColumn) {
2984         TableColumnModel cm = getColumnModel();
2985         for (int column = 0; column < cm.getColumnCount(); column++) {
2986             if (cm.getColumn(column) == aColumn) {
2987                 return column;
2988             }
2989         }
2990         return -1;
2991     }
2992 
2993     /**
2994      * Causes this table to lay out its rows and columns.  Overridden so
2995      * that columns can be resized to accomodate a change in the size of
2996      * a containing parent.
2997      * Resizes one or more of the columns in the table
2998      * so that the total width of all of this <code>JTable</code>'s
2999      * columns is equal to the width of the table.
3000      * <p>
3001      * Before the layout begins the method gets the
3002      * <code>resizingColumn</code> of the <code>tableHeader</code>.
3003      * When the method is called as a result of the resizing of an enclosing window,
3004      * the <code>resizingColumn</code> is <code>null</code>. This means that resizing
3005      * has taken place "outside" the <code>JTable</code> and the change -
3006      * or "delta" - should be distributed to all of the columns regardless
3007      * of this <code>JTable</code>'s automatic resize mode.
3008      * <p>
3009      * If the <code>resizingColumn</code> is not <code>null</code>, it is one of
3010      * the columns in the table that has changed size rather than
3011      * the table itself. In this case the auto-resize modes govern
3012      * the way the extra (or deficit) space is distributed
3013      * amongst the available columns.
3014      * <p>
3015      * The modes are:
3016      * <ul>
3017      * <li>  AUTO_RESIZE_OFF: Don't automatically adjust the column's
3018      * widths at all. Use a horizontal scrollbar to accomodate the
3019      * columns when their sum exceeds the width of the
3020      * <code>Viewport</code>.  If the <code>JTable</code> is not
3021      * enclosed in a <code>JScrollPane</code> this may
3022      * leave parts of the table invisible.
3023      * <li>  AUTO_RESIZE_NEXT_COLUMN: Use just the column after the
3024      * resizing column. This results in the "boundary" or divider
3025      * between adjacent cells being independently adjustable.
3026      * <li>  AUTO_RESIZE_SUBSEQUENT_COLUMNS: Use all columns after the
3027      * one being adjusted to absorb the changes.  This is the
3028      * default behavior.
3029      * <li>  AUTO_RESIZE_LAST_COLUMN: Automatically adjust the
3030      * size of the last column only. If the bounds of the last column
3031      * prevent the desired size from being allocated, set the
3032      * width of the last column to the appropriate limit and make
3033      * no further adjustments.
3034      * <li>  AUTO_RESIZE_ALL_COLUMNS: Spread the delta amongst all the columns
3035      * in the <code>JTable</code>, including the one that is being
3036      * adjusted.
3037      * </ul>
3038      * <p>
3039      * <bold>Note:</bold> When a <code>JTable</code> makes adjustments
3040      *   to the widths of the columns it respects their minimum and
3041      *   maximum values absolutely.  It is therefore possible that,
3042      *   even after this method is called, the total width of the columns
3043      *   is still not equal to the width of the table. When this happens
3044      *   the <code>JTable</code> does not put itself
3045      *   in AUTO_RESIZE_OFF mode to bring up a scroll bar, or break other
3046      *   commitments of its current auto-resize mode -- instead it
3047      *   allows its bounds to be set larger (or smaller) than the total of the
3048      *   column minimum or maximum, meaning, either that there
3049      *   will not be enough room to display all of the columns, or that the
3050      *   columns will not fill the <code>JTable</code>'s bounds.
3051      *   These respectively, result in the clipping of some columns
3052      *   or an area being painted in the <code>JTable</code>'s
3053      *   background color during painting.
3054      * <p>
3055      *   The mechanism for distributing the delta amongst the available
3056      *   columns is provided in a private method in the <code>JTable</code>
3057      *   class:
3058      * <pre>
3059      *   adjustSizes(long targetSize, final Resizable3 r, boolean inverse)
3060      * </pre>
3061      *   an explanation of which is provided in the following section.
3062      *   <code>Resizable3</code> is a private
3063      *   interface that allows any data structure containing a collection
3064      *   of elements with a size, preferred size, maximum size and minimum size
3065      *   to have its elements manipulated by the algorithm.
3066      * <p>
3067      * <H3> Distributing the delta </H3>
3068      * <p>
3069      * <H4> Overview </H4>
3070      * <P>
3071      * Call "DELTA" the difference between the target size and the
3072      * sum of the preferred sizes of the elements in r. The individual
3073      * sizes are calculated by taking the original preferred
3074      * sizes and adding a share of the DELTA - that share being based on
3075      * how far each preferred size is from its limiting bound (minimum or
3076      * maximum).
3077      * <p>
3078      * <H4>Definition</H4>
3079      * <P>
3080      * Call the individual constraints min[i], max[i], and pref[i].
3081      * <p>
3082      * Call their respective sums: MIN, MAX, and PREF.
3083      * <p>
3084      * Each new size will be calculated using:
3085      * <p>
3086      * <pre>
3087      *          size[i] = pref[i] + delta[i]
3088      * </pre>
3089      * where each individual delta[i] is calculated according to:
3090      * <p>
3091      * If (DELTA < 0) we are in shrink mode where:
3092      * <p>
3093      * <PRE>
3094      *                        DELTA
3095      *          delta[i] = ------------ * (pref[i] - min[i])
3096      *                     (PREF - MIN)
3097      * </PRE>
3098      * If (DELTA > 0) we are in expand mode where:
3099      * <p>
3100      * <PRE>
3101      *                        DELTA
3102      *          delta[i] = ------------ * (max[i] - pref[i])
3103      *                      (MAX - PREF)
3104      * </PRE>
3105      * <P>
3106      * The overall effect is that the total size moves that same percentage,
3107      * k, towards the total minimum or maximum and that percentage guarantees
3108      * accomodation of the required space, DELTA.
3109      *
3110      * <H4>Details</H4>
3111      * <P>
3112      * Naive evaluation of the formulae presented here would be subject to
3113      * the aggregated rounding errors caused by doing this operation in finite
3114      * precision (using ints). To deal with this, the multiplying factor above,
3115      * is constantly recalculated and this takes account of the rounding
3116      * errors in the previous iterations. The result is an algorithm that
3117      * produces a set of integers whose values exactly sum to the supplied
3118      * <code>targetSize</code>, and does so by spreading the rounding
3119      * errors evenly over the given elements.
3120      *
3121      * <H4>When the MAX and MIN bounds are hit</H4>
3122      * <P>
3123      * When <code>targetSize</code> is outside the [MIN, MAX] range,
3124      * the algorithm sets all sizes to their appropriate limiting value
3125      * (maximum or minimum).
3126      *
3127      */
3128     public void doLayout() {
3129         TableColumn resizingColumn = getResizingColumn();
3130         if (resizingColumn == null) {
3131             setWidthsFromPreferredWidths(false);
3132         }
3133         else {
3134             // JTable behaves like a layout manger - but one in which the
3135             // user can come along and dictate how big one of the children
3136             // (columns) is supposed to be.
3137 
3138             // A column has been resized and JTable may need to distribute
3139             // any overall delta to other columns, according to the resize mode.
3140             int columnIndex = viewIndexForColumn(resizingColumn);
3141             int delta = getWidth() - getColumnModel().getTotalColumnWidth();
3142             accommodateDelta(columnIndex, delta);
3143             delta = getWidth() - getColumnModel().getTotalColumnWidth();
3144 
3145             // If the delta cannot be completely accomodated, then the
3146             // resizing column will have to take any remainder. This means
3147             // that the column is not being allowed to take the requested
3148             // width. This happens under many circumstances: For example,
3149             // AUTO_RESIZE_NEXT_COLUMN specifies that any delta be distributed
3150             // to the column after the resizing column. If one were to attempt
3151             // to resize the last column of the table, there would be no
3152             // columns after it, and hence nowhere to distribute the delta.
3153             // It would then be given entirely back to the resizing column,
3154             // preventing it from changing size.
3155             if (delta != 0) {
3156                 resizingColumn.setWidth(resizingColumn.getWidth() + delta);
3157             }
3158 
3159             // At this point the JTable has to work out what preferred sizes
3160             // would have resulted in the layout the user has chosen.
3161             // Thereafter, during window resizing etc. it has to work off
3162             // the preferred sizes as usual - the idea being that, whatever
3163             // the user does, everything stays in synch and things don't jump
3164             // around.
3165             setWidthsFromPreferredWidths(true);
3166         }
3167 
3168         super.doLayout();
3169     }
3170 
3171     private TableColumn getResizingColumn() {
3172         return (tableHeader == null) ? null
3173                                      : tableHeader.getResizingColumn();
3174     }
3175 
3176     /**
3177      * Sizes the table columns to fit the available space.
3178      * @deprecated As of Swing version 1.0.3,
3179      * replaced by <code>doLayout()</code>.
3180      * @see #doLayout
3181      */
3182     @Deprecated
3183     public void sizeColumnsToFit(boolean lastColumnOnly) {
3184         int oldAutoResizeMode = autoResizeMode;
3185         setAutoResizeMode(lastColumnOnly ? AUTO_RESIZE_LAST_COLUMN
3186                                          : AUTO_RESIZE_ALL_COLUMNS);
3187         sizeColumnsToFit(-1);
3188         setAutoResizeMode(oldAutoResizeMode);
3189     }
3190 
3191     /**
3192      * Obsolete as of Java 2 platform v1.4.  Please use the
3193      * <code>doLayout()</code> method instead.
3194      * @param resizingColumn    the column whose resizing made this adjustment
3195      *                          necessary or -1 if there is no such column
3196      * @see  #doLayout
3197      */
3198     public void sizeColumnsToFit(int resizingColumn) {
3199         if (resizingColumn == -1) {
3200             setWidthsFromPreferredWidths(false);
3201         }
3202         else {
3203             if (autoResizeMode == AUTO_RESIZE_OFF) {
3204                 TableColumn aColumn = getColumnModel().getColumn(resizingColumn);
3205                 aColumn.setPreferredWidth(aColumn.getWidth());
3206             }
3207             else {
3208                 int delta = getWidth() - getColumnModel().getTotalColumnWidth();
3209                 accommodateDelta(resizingColumn, delta);
3210                 setWidthsFromPreferredWidths(true);
3211             }
3212         }
3213     }
3214 
3215     private void setWidthsFromPreferredWidths(final boolean inverse) {
3216         int totalWidth     = getWidth();
3217         int totalPreferred = getPreferredSize().width;
3218         int target = !inverse ? totalWidth : totalPreferred;
3219 
3220         final TableColumnModel cm = columnModel;
3221         Resizable3 r = new Resizable3() {
3222             public int  getElementCount()      { return cm.getColumnCount(); }
3223             public int  getLowerBoundAt(int i) { return cm.getColumn(i).getMinWidth(); }
3224             public int  getUpperBoundAt(int i) { return cm.getColumn(i).getMaxWidth(); }
3225             public int  getMidPointAt(int i)  {
3226                 if (!inverse) {
3227                     return cm.getColumn(i).getPreferredWidth();
3228                 }
3229                 else {
3230                     return cm.getColumn(i).getWidth();
3231                 }
3232             }
3233             public void setSizeAt(int s, int i) {
3234                 if (!inverse) {
3235                     cm.getColumn(i).setWidth(s);
3236                 }
3237                 else {
3238                     cm.getColumn(i).setPreferredWidth(s);
3239                 }
3240             }
3241         };
3242 
3243         adjustSizes(target, r, inverse);
3244     }
3245 
3246 
3247     // Distribute delta over columns, as indicated by the autoresize mode.
3248     private void accommodateDelta(int resizingColumnIndex, int delta) {
3249         int columnCount = getColumnCount();
3250         int from = resizingColumnIndex;
3251         int to;
3252 
3253         // Use the mode to determine how to absorb the changes.
3254         switch(autoResizeMode) {
3255             case AUTO_RESIZE_NEXT_COLUMN:
3256                 from = from + 1;
3257                 to = Math.min(from + 1, columnCount); break;
3258             case AUTO_RESIZE_SUBSEQUENT_COLUMNS:
3259                 from = from + 1;
3260                 to = columnCount; break;
3261             case AUTO_RESIZE_LAST_COLUMN:
3262                 from = columnCount - 1;
3263                 to = from + 1; break;
3264             case AUTO_RESIZE_ALL_COLUMNS:
3265                 from = 0;
3266                 to = columnCount; break;
3267             default:
3268                 return;
3269         }
3270 
3271         final int start = from;
3272         final int end = to;
3273         final TableColumnModel cm = columnModel;
3274         Resizable3 r = new Resizable3() {
3275             public int  getElementCount()       { return end-start; }
3276             public int  getLowerBoundAt(int i)  { return cm.getColumn(i+start).getMinWidth(); }
3277             public int  getUpperBoundAt(int i)  { return cm.getColumn(i+start).getMaxWidth(); }
3278             public int  getMidPointAt(int i)    { return cm.getColumn(i+start).getWidth(); }
3279             public void setSizeAt(int s, int i) {        cm.getColumn(i+start).setWidth(s); }
3280         };
3281 
3282         int totalWidth = 0;
3283         for(int i = from; i < to; i++) {
3284             TableColumn aColumn = columnModel.getColumn(i);
3285             int input = aColumn.getWidth();
3286             totalWidth = totalWidth + input;
3287         }
3288 
3289         adjustSizes(totalWidth + delta, r, false);
3290     }
3291 
3292     private interface Resizable2 {
3293         public int  getElementCount();
3294         public int  getLowerBoundAt(int i);
3295         public int  getUpperBoundAt(int i);
3296         public void setSizeAt(int newSize, int i);
3297     }
3298 
3299     private interface Resizable3 extends Resizable2 {
3300         public int  getMidPointAt(int i);
3301     }
3302 
3303 
3304     private void adjustSizes(long target, final Resizable3 r, boolean inverse) {
3305         int N = r.getElementCount();
3306         long totalPreferred = 0;
3307         for(int i = 0; i < N; i++) {
3308             totalPreferred += r.getMidPointAt(i);
3309         }
3310         Resizable2 s;
3311         if ((target < totalPreferred) == !inverse) {
3312             s = new Resizable2() {
3313                 public int  getElementCount()      { return r.getElementCount(); }
3314                 public int  getLowerBoundAt(int i) { return r.getLowerBoundAt(i); }
3315                 public int  getUpperBoundAt(int i) { return r.getMidPointAt(i); }
3316                 public void setSizeAt(int newSize, int i) { r.setSizeAt(newSize, i); }
3317 
3318             };
3319         }
3320         else {
3321             s = new Resizable2() {
3322                 public int  getElementCount()      { return r.getElementCount(); }
3323                 public int  getLowerBoundAt(int i) { return r.getMidPointAt(i); }
3324                 public int  getUpperBoundAt(int i) { return r.getUpperBoundAt(i); }
3325                 public void setSizeAt(int newSize, int i) { r.setSizeAt(newSize, i); }
3326 
3327             };
3328         }
3329         adjustSizes(target, s, !inverse);
3330     }
3331 
3332     private void adjustSizes(long target, Resizable2 r, boolean limitToRange) {
3333         long totalLowerBound = 0;
3334         long totalUpperBound = 0;
3335         for(int i = 0; i < r.getElementCount(); i++) {
3336             totalLowerBound += r.getLowerBoundAt(i);
3337             totalUpperBound += r.getUpperBoundAt(i);
3338         }
3339 
3340         if (limitToRange) {
3341             target = Math.min(Math.max(totalLowerBound, target), totalUpperBound);
3342         }
3343 
3344         for(int i = 0; i < r.getElementCount(); i++) {
3345             int lowerBound = r.getLowerBoundAt(i);
3346             int upperBound = r.getUpperBoundAt(i);
3347             // Check for zero. This happens when the distribution of the delta
3348             // finishes early due to a series of "fixed" entries at the end.
3349             // In this case, lowerBound == upperBound, for all subsequent terms.
3350             int newSize;
3351             if (totalLowerBound == totalUpperBound) {
3352                 newSize = lowerBound;
3353             }
3354             else {
3355                 double f = (double)(target - totalLowerBound)/(totalUpperBound - totalLowerBound);
3356                 newSize = (int)Math.round(lowerBound+f*(upperBound - lowerBound));
3357                 // We'd need to round manually in an all integer version.
3358                 // size[i] = (int)(((totalUpperBound - target) * lowerBound +
3359                 //     (target - totalLowerBound) * upperBound)/(totalUpperBound-totalLowerBound));
3360             }
3361             r.setSizeAt(newSize, i);
3362             target -= newSize;
3363             totalLowerBound -= lowerBound;
3364             totalUpperBound -= upperBound;
3365         }
3366     }
3367 
3368     /**
3369      * Overrides <code>JComponent</code>'s <code>getToolTipText</code>
3370      * method in order to allow the renderer's tips to be used
3371      * if it has text set.
3372      * <p>
3373      * <bold>Note:</bold> For <code>JTable</code> to properly display
3374      * tooltips of its renderers
3375      * <code>JTable</code> must be a registered component with the
3376      * <code>ToolTipManager</code>.
3377      * This is done automatically in <code>initializeLocalVars</code>,
3378      * but if at a later point <code>JTable</code> is told
3379      * <code>setToolTipText(null)</code> it will unregister the table
3380      * component, and no tips from renderers will display anymore.
3381      *
3382      * @see JComponent#getToolTipText
3383      */
3384     public String getToolTipText(MouseEvent event) {
3385         String tip = null;
3386         Point p = event.getPoint();
3387 
3388         // Locate the renderer under the event location
3389         int hitColumnIndex = columnAtPoint(p);
3390         int hitRowIndex = rowAtPoint(p);
3391 
3392         if ((hitColumnIndex != -1) && (hitRowIndex != -1)) {
3393             TableCellRenderer renderer = getCellRenderer(hitRowIndex, hitColumnIndex);
3394             Component component = prepareRenderer(renderer, hitRowIndex, hitColumnIndex);
3395 
3396             // Now have to see if the component is a JComponent before
3397             // getting the tip
3398             if (component instanceof JComponent) {
3399                 // Convert the event to the renderer's coordinate system
3400                 Rectangle cellRect = getCellRect(hitRowIndex, hitColumnIndex, false);
3401                 p.translate(-cellRect.x, -cellRect.y);
3402                 MouseEvent newEvent = new MouseEvent(component, event.getID(),
3403                                           event.getWhen(), event.getModifiers(),
3404                                           p.x, p.y,
3405                                           event.getXOnScreen(),
3406                                           event.getYOnScreen(),
3407                                           event.getClickCount(),
3408                                           event.isPopupTrigger(),
3409                                           MouseEvent.NOBUTTON);
3410 
3411                 tip = ((JComponent)component).getToolTipText(newEvent);
3412             }
3413         }
3414 
3415         // No tip from the renderer get our own tip
3416         if (tip == null)
3417             tip = getToolTipText();
3418 
3419         return tip;
3420     }
3421 
3422 //
3423 // Editing Support
3424 //
3425 
3426     /**
3427      * Sets whether editors in this JTable get the keyboard focus
3428      * when an editor is activated as a result of the JTable
3429      * forwarding keyboard events for a cell.
3430      * By default, this property is false, and the JTable
3431      * retains the focus unless the cell is clicked.
3432      *
3433      * @param surrendersFocusOnKeystroke true if the editor should get the focus
3434      *          when keystrokes cause the editor to be
3435      *          activated
3436      *
3437      *
3438      * @see #getSurrendersFocusOnKeystroke
3439      * @since 1.4
3440      */
3441     public void setSurrendersFocusOnKeystroke(boolean surrendersFocusOnKeystroke) {
3442         this.surrendersFocusOnKeystroke = surrendersFocusOnKeystroke;
3443     }
3444 
3445     /**
3446      * Returns true if the editor should get the focus
3447      * when keystrokes cause the editor to be activated
3448      *
3449      * @return  true if the editor should get the focus
3450      *          when keystrokes cause the editor to be
3451      *          activated
3452      *
3453      * @see #setSurrendersFocusOnKeystroke
3454      * @since 1.4
3455      */
3456     public boolean getSurrendersFocusOnKeystroke() {
3457         return surrendersFocusOnKeystroke;
3458     }
3459 
3460     /**
3461      * Programmatically starts editing the cell at <code>row</code> and
3462      * <code>column</code>, if those indices are in the valid range, and
3463      * the cell at those indices is editable.
3464      * Note that this is a convenience method for
3465      * <code>editCellAt(int, int, null)</code>.
3466      *
3467      * @param   row                             the row to be edited
3468      * @param   column                          the column to be edited
3469      * @return  false if for any reason the cell cannot be edited,
3470      *                or if the indices are invalid
3471      */
3472     public boolean editCellAt(int row, int column) {
3473         return editCellAt(row, column, null);
3474     }
3475 
3476     /**
3477      * Programmatically starts editing the cell at <code>row</code> and
3478      * <code>column</code>, if those indices are in the valid range, and
3479      * the cell at those indices is editable.
3480      * To prevent the <code>JTable</code> from
3481      * editing a particular table, column or cell value, return false from
3482      * the <code>isCellEditable</code> method in the <code>TableModel</code>
3483      * interface.
3484      *
3485      * @param   row     the row to be edited
3486      * @param   column  the column to be edited
3487      * @param   e       event to pass into <code>shouldSelectCell</code>;
3488      *                  note that as of Java 2 platform v1.2, the call to
3489      *                  <code>shouldSelectCell</code> is no longer made
3490      * @return  false if for any reason the cell cannot be edited,
3491      *                or if the indices are invalid
3492      */
3493     public boolean editCellAt(int row, int column, EventObject e){
3494         if (cellEditor != null && !cellEditor.stopCellEditing()) {
3495             return false;
3496         }
3497 
3498         if (row < 0 || row >= getRowCount() ||
3499             column < 0 || column >= getColumnCount()) {
3500             return false;
3501         }
3502 
3503         if (!isCellEditable(row, column))
3504             return false;
3505 
3506         if (editorRemover == null) {
3507             KeyboardFocusManager fm =
3508                 KeyboardFocusManager.getCurrentKeyboardFocusManager();
3509             editorRemover = new CellEditorRemover(fm);
3510             fm.addPropertyChangeListener("permanentFocusOwner", editorRemover);
3511         }
3512 
3513         TableCellEditor editor = getCellEditor(row, column);
3514         if (editor != null && editor.isCellEditable(e)) {
3515             editorComp = prepareEditor(editor, row, column);
3516             if (editorComp == null) {
3517                 removeEditor();
3518                 return false;
3519             }
3520             editorComp.setBounds(getCellRect(row, column, false));
3521             add(editorComp);
3522             editorComp.validate();
3523             editorComp.repaint();
3524 
3525             setCellEditor(editor);
3526             setEditingRow(row);
3527             setEditingColumn(column);
3528             editor.addCellEditorListener(this);
3529 
3530             return true;
3531         }
3532         return false;
3533     }
3534 
3535     /**
3536      * Returns true if a cell is being edited.
3537      *
3538      * @return  true if the table is editing a cell
3539      * @see     #editingColumn
3540      * @see     #editingRow
3541      */
3542     public boolean isEditing() {
3543         return cellEditor != null;
3544     }
3545 
3546     /**
3547      * Returns the component that is handling the editing session.
3548      * If nothing is being edited, returns null.
3549      *
3550      * @return  Component handling editing session
3551      */
3552     public Component getEditorComponent() {
3553         return editorComp;
3554     }
3555 
3556     /**
3557      * Returns the index of the column that contains the cell currently
3558      * being edited.  If nothing is being edited, returns -1.
3559      *
3560      * @return  the index of the column that contains the cell currently
3561      *          being edited; returns -1 if nothing being edited
3562      * @see #editingRow
3563      */
3564     public int getEditingColumn() {
3565         return editingColumn;
3566     }
3567 
3568     /**
3569      * Returns the index of the row that contains the cell currently
3570      * being edited.  If nothing is being edited, returns -1.
3571      *
3572      * @return  the index of the row that contains the cell currently
3573      *          being edited; returns -1 if nothing being edited
3574      * @see #editingColumn
3575      */
3576     public int getEditingRow() {
3577         return editingRow;
3578     }
3579 
3580 //
3581 // Managing TableUI
3582 //
3583 
3584     /**
3585      * Returns the L&F object that renders this component.
3586      *
3587      * @return the <code>TableUI</code> object that renders this component
3588      */
3589     public TableUI getUI() {
3590         return (TableUI)ui;
3591     }
3592 
3593     /**
3594      * Sets the L&F object that renders this component and repaints.
3595      *
3596      * @param ui  the TableUI L&F object
3597      * @see UIDefaults#getUI
3598      * @beaninfo
3599      *        bound: true
3600      *       hidden: true
3601      *    attribute: visualUpdate true
3602      *  description: The UI object that implements the Component's LookAndFeel.
3603      */
3604     public void setUI(TableUI ui) {
3605         if (this.ui != ui) {
3606             super.setUI(ui);
3607             repaint();
3608         }
3609     }
3610 
3611     /**
3612      * Notification from the <code>UIManager</code> that the L&F has changed.
3613      * Replaces the current UI object with the latest version from the
3614      * <code>UIManager</code>.
3615      *
3616      * @see JComponent#updateUI
3617      */
3618     public void updateUI() {
3619         // Update the UIs of the cell renderers, cell editors and header renderers.
3620         TableColumnModel cm = getColumnModel();
3621         for(int column = 0; column < cm.getColumnCount(); column++) {
3622             TableColumn aColumn = cm.getColumn(column);
3623             SwingUtilities.updateRendererOrEditorUI(aColumn.getCellRenderer());
3624             SwingUtilities.updateRendererOrEditorUI(aColumn.getCellEditor());
3625             SwingUtilities.updateRendererOrEditorUI(aColumn.getHeaderRenderer());
3626         }
3627 
3628         // Update the UIs of all the default renderers.
3629         Enumeration defaultRenderers = defaultRenderersByColumnClass.elements();
3630         while (defaultRenderers.hasMoreElements()) {
3631             SwingUtilities.updateRendererOrEditorUI(defaultRenderers.nextElement());
3632         }
3633 
3634         // Update the UIs of all the default editors.
3635         Enumeration defaultEditors = defaultEditorsByColumnClass.elements();
3636         while (defaultEditors.hasMoreElements()) {
3637             SwingUtilities.updateRendererOrEditorUI(defaultEditors.nextElement());
3638         }
3639 
3640         // Update the UI of the table header
3641         if (tableHeader != null && tableHeader.getParent() == null) {
3642             tableHeader.updateUI();
3643         }
3644 
3645         // Update UI applied to parent ScrollPane
3646         configureEnclosingScrollPaneUI();
3647 
3648         setUI((TableUI)UIManager.getUI(this));
3649     }
3650 
3651     /**
3652      * Returns the suffix used to construct the name of the L&F class used to
3653      * render this component.
3654      *
3655      * @return the string "TableUI"
3656      * @see JComponent#getUIClassID
3657      * @see UIDefaults#getUI
3658      */
3659     public String getUIClassID() {
3660         return uiClassID;
3661     }
3662 
3663 
3664 //
3665 // Managing models
3666 //
3667 
3668     /**
3669      * Sets the data model for this table to <code>newModel</code> and registers
3670      * with it for listener notifications from the new data model.
3671      *
3672      * @param   dataModel        the new data source for this table
3673      * @exception IllegalArgumentException      if <code>newModel</code> is <code>null</code>
3674      * @see     #getModel
3675      * @beaninfo
3676      *  bound: true
3677      *  description: The model that is the source of the data for this view.
3678      */
3679     public void setModel(TableModel dataModel) {
3680         if (dataModel == null) {
3681             throw new IllegalArgumentException("Cannot set a null TableModel");
3682         }
3683         if (this.dataModel != dataModel) {
3684             TableModel old = this.dataModel;
3685             if (old != null) {
3686                 old.removeTableModelListener(this);
3687             }
3688             this.dataModel = dataModel;
3689             dataModel.addTableModelListener(this);
3690 
3691             tableChanged(new TableModelEvent(dataModel, TableModelEvent.HEADER_ROW));
3692 
3693             firePropertyChange("model", old, dataModel);
3694 
3695             if (getAutoCreateRowSorter()) {
3696                 setRowSorter(new TableRowSorter<TableModel>(dataModel));
3697             }
3698         }
3699     }
3700 
3701     /**
3702      * Returns the <code>TableModel</code> that provides the data displayed by this
3703      * <code>JTable</code>.
3704      *
3705      * @return  the <code>TableModel</code> that provides the data displayed by this <code>JTable</code>
3706      * @see     #setModel
3707      */
3708     public TableModel getModel() {
3709         return dataModel;
3710     }
3711 
3712     /**
3713      * Sets the column model for this table to <code>newModel</code> and registers
3714      * for listener notifications from the new column model. Also sets
3715      * the column model of the <code>JTableHeader</code> to <code>columnModel</code>.
3716      *
3717      * @param   columnModel        the new data source for this table
3718      * @exception IllegalArgumentException      if <code>columnModel</code> is <code>null</code>
3719      * @see     #getColumnModel
3720      * @beaninfo
3721      *  bound: true
3722      *  description: The object governing the way columns appear in the view.
3723      */
3724     public void setColumnModel(TableColumnModel columnModel) {
3725         if (columnModel == null) {
3726             throw new IllegalArgumentException("Cannot set a null ColumnModel");
3727         }
3728         TableColumnModel old = this.columnModel;
3729         if (columnModel != old) {
3730             if (old != null) {
3731                 old.removeColumnModelListener(this);
3732             }
3733             this.columnModel = columnModel;
3734             columnModel.addColumnModelListener(this);
3735 
3736             // Set the column model of the header as well.
3737             if (tableHeader != null) {
3738                 tableHeader.setColumnModel(columnModel);
3739             }
3740 
3741             firePropertyChange("columnModel", old, columnModel);
3742             resizeAndRepaint();
3743         }
3744     }
3745 
3746     /**
3747      * Returns the <code>TableColumnModel</code> that contains all column information
3748      * of this table.
3749      *
3750      * @return  the object that provides the column state of the table
3751      * @see     #setColumnModel
3752      */
3753     public TableColumnModel getColumnModel() {
3754         return columnModel;
3755     }
3756 
3757     /**
3758      * Sets the row selection model for this table to <code>newModel</code>
3759      * and registers for listener notifications from the new selection model.
3760      *
3761      * @param   newModel        the new selection model
3762      * @exception IllegalArgumentException      if <code>newModel</code> is <code>null</code>
3763      * @see     #getSelectionModel
3764      * @beaninfo
3765      *      bound: true
3766      *      description: The selection model for rows.
3767      */
3768     public void setSelectionModel(ListSelectionModel newModel) {
3769         if (newModel == null) {
3770             throw new IllegalArgumentException("Cannot set a null SelectionModel");
3771         }
3772 
3773         ListSelectionModel oldModel = selectionModel;
3774 
3775         if (newModel != oldModel) {
3776             if (oldModel != null) {
3777                 oldModel.removeListSelectionListener(this);
3778             }
3779 
3780             selectionModel = newModel;
3781             newModel.addListSelectionListener(this);
3782 
3783             firePropertyChange("selectionModel", oldModel, newModel);
3784             repaint();
3785         }
3786     }
3787 
3788     /**
3789      * Returns the <code>ListSelectionModel</code> that is used to maintain row
3790      * selection state.
3791      *
3792      * @return  the object that provides row selection state, <code>null</code>
3793      *          if row selection is not allowed
3794      * @see     #setSelectionModel
3795      */
3796     public ListSelectionModel getSelectionModel() {
3797         return selectionModel;
3798     }
3799 
3800 //
3801 // RowSorterListener
3802 //
3803 
3804     /**
3805      * <code>RowSorterListener</code> notification that the
3806      * <code>RowSorter</code> has changed in some way.
3807      *
3808      * @param e the <code>RowSorterEvent</code> describing the change
3809      * @throws NullPointerException if <code>e</code> is <code>null</code>
3810      * @since 1.6
3811      */
3812     public void sorterChanged(RowSorterEvent e) {
3813         if (e.getType() == RowSorterEvent.Type.SORT_ORDER_CHANGED) {
3814             JTableHeader header = getTableHeader();
3815             if (header != null) {
3816                 header.repaint();
3817             }
3818         }
3819         else if (e.getType() == RowSorterEvent.Type.SORTED) {
3820             sorterChanged = true;
3821             if (!ignoreSortChange) {
3822                 sortedTableChanged(e, null);
3823             }
3824         }
3825     }
3826 
3827 
3828     /**
3829      * SortManager provides support for managing the selection and variable
3830      * row heights when sorting is enabled. This information is encapsulated
3831      * into a class to avoid bulking up JTable.
3832      */
3833     private final class SortManager {
3834         RowSorter<? extends TableModel> sorter;
3835 
3836         // Selection, in terms of the model. This is lazily created
3837         // as needed.
3838         private ListSelectionModel modelSelection;
3839         private int modelLeadIndex;
3840         // Set to true while in the process of changing the selection.
3841         // If this is true the selection change is ignored.
3842         private boolean syncingSelection;
3843         // Temporary cache of selection, in terms of model. This is only used
3844         // if we don't need the full weight of modelSelection.
3845         private int[] lastModelSelection;
3846 
3847         // Heights of the rows in terms of the model.
3848         private SizeSequence modelRowSizes;
3849 
3850 
3851         SortManager(RowSorter<? extends TableModel> sorter) {
3852             this.sorter = sorter;
3853             sorter.addRowSorterListener(JTable.this);
3854         }
3855 
3856         /**
3857          * Disposes any resources used by this SortManager.
3858          */
3859         public void dispose() {
3860             if (sorter != null) {
3861                 sorter.removeRowSorterListener(JTable.this);
3862             }
3863         }
3864 
3865         /**
3866          * Sets the height for a row at a specified index.
3867          */
3868         public void setViewRowHeight(int viewIndex, int rowHeight) {
3869             if (modelRowSizes == null) {
3870                 modelRowSizes = new SizeSequence(getModel().getRowCount(),
3871                                                  getRowHeight());
3872             }
3873             modelRowSizes.setSize(convertRowIndexToModel(viewIndex),rowHeight);
3874         }
3875 
3876         /**
3877          * Invoked when the underlying model has completely changed.
3878          */
3879         public void allChanged() {
3880             modelLeadIndex = -1;
3881             modelSelection = null;
3882             modelRowSizes = null;
3883         }
3884 
3885         /**
3886          * Invoked when the selection, on the view, has changed.
3887          */
3888         public void viewSelectionChanged(ListSelectionEvent e) {
3889             if (!syncingSelection && modelSelection != null) {
3890                 modelSelection = null;
3891             }
3892         }
3893 
3894         /**
3895          * Invoked when either the table model has changed, or the RowSorter
3896          * has changed. This is invoked prior to notifying the sorter of the
3897          * change.
3898          */
3899         public void prepareForChange(RowSorterEvent sortEvent,
3900                                      ModelChange change) {
3901             if (getUpdateSelectionOnSort()) {
3902                 cacheSelection(sortEvent, change);
3903             }
3904         }
3905 
3906         /**
3907          * Updates the internal cache of the selection based on the change.
3908          */
3909         private void cacheSelection(RowSorterEvent sortEvent,
3910                                     ModelChange change) {
3911             if (sortEvent != null) {
3912                 // sort order changed. If modelSelection is null and filtering
3913                 // is enabled we need to cache the selection in terms of the
3914                 // underlying model, this will allow us to correctly restore
3915                 // the selection even if rows are filtered out.
3916                 if (modelSelection == null &&
3917                         sorter.getViewRowCount() != getModel().getRowCount()) {
3918                     modelSelection = new DefaultListSelectionModel();
3919                     ListSelectionModel viewSelection = getSelectionModel();
3920                     int min = viewSelection.getMinSelectionIndex();
3921                     int max = viewSelection.getMaxSelectionIndex();
3922                     int modelIndex;
3923                     for (int viewIndex = min; viewIndex <= max; viewIndex++) {
3924                         if (viewSelection.isSelectedIndex(viewIndex)) {
3925                             modelIndex = convertRowIndexToModel(
3926                                     sortEvent, viewIndex);
3927                             if (modelIndex != -1) {
3928                                 modelSelection.addSelectionInterval(
3929                                     modelIndex, modelIndex);
3930                             }
3931                         }
3932                     }
3933                     modelIndex = convertRowIndexToModel(sortEvent,
3934                             viewSelection.getLeadSelectionIndex());
3935                     SwingUtilities2.setLeadAnchorWithoutSelection(
3936                             modelSelection, modelIndex, modelIndex);
3937                 } else if (modelSelection == null) {
3938                     // Sorting changed, haven't cached selection in terms
3939                     // of model and no filtering. Temporarily cache selection.
3940                     cacheModelSelection(sortEvent);
3941                 }
3942             } else if (change.allRowsChanged) {
3943                 // All the rows have changed, chuck any cached selection.
3944                 modelSelection = null;
3945             } else if (modelSelection != null) {
3946                 // Table changed, reflect changes in cached selection model.
3947                 switch(change.type) {
3948                 case TableModelEvent.DELETE:
3949                     modelSelection.removeIndexInterval(change.startModelIndex,
3950                                                        change.endModelIndex);
3951                     break;
3952                 case TableModelEvent.INSERT:
3953                     modelSelection.insertIndexInterval(change.startModelIndex,
3954                                                        change.endModelIndex,
3955                                                        true);
3956                     break;
3957                 default:
3958                     break;
3959                 }
3960             } else {
3961                 // table changed, but haven't cached rows, temporarily
3962                 // cache them.
3963                 cacheModelSelection(null);
3964             }
3965         }
3966 
3967         private void cacheModelSelection(RowSorterEvent sortEvent) {
3968             lastModelSelection = convertSelectionToModel(sortEvent);
3969             modelLeadIndex = convertRowIndexToModel(sortEvent,
3970                         selectionModel.getLeadSelectionIndex());
3971         }
3972 
3973         /**
3974          * Inovked when either the table has changed or the sorter has changed
3975          * and after the sorter has been notified. If necessary this will
3976          * reapply the selection and variable row heights.
3977          */
3978         public void processChange(RowSorterEvent sortEvent,
3979                                   ModelChange change,
3980                                   boolean sorterChanged) {
3981             if (change != null) {
3982                 if (change.allRowsChanged) {
3983                     modelRowSizes = null;
3984                     rowModel = null;
3985                 } else if (modelRowSizes != null) {
3986                     if (change.type == TableModelEvent.INSERT) {
3987                         modelRowSizes.insertEntries(change.startModelIndex,
3988                                                     change.endModelIndex -
3989                                                     change.startModelIndex + 1,
3990                                                     getRowHeight());
3991                     } else if (change.type == TableModelEvent.DELETE) {
3992                         modelRowSizes.removeEntries(change.startModelIndex,
3993                                                     change.endModelIndex -
3994                                                     change.startModelIndex +1 );
3995                     }
3996                 }
3997             }
3998             if (sorterChanged) {
3999                 setViewRowHeightsFromModel();
4000                 restoreSelection(change);
4001             }
4002         }
4003 
4004         /**
4005          * Resets the variable row heights in terms of the view from
4006          * that of the variable row heights in terms of the model.
4007          */
4008         private void setViewRowHeightsFromModel() {
4009             if (modelRowSizes != null) {
4010                 rowModel.setSizes(getRowCount(), getRowHeight());
4011                 for (int viewIndex = getRowCount() - 1; viewIndex >= 0;
4012                          viewIndex--) {
4013                     int modelIndex = convertRowIndexToModel(viewIndex);
4014                     rowModel.setSize(viewIndex,
4015                                      modelRowSizes.getSize(modelIndex));
4016                 }
4017             }
4018         }
4019 
4020         /**
4021          * Restores the selection from that in terms of the model.
4022          */
4023         private void restoreSelection(ModelChange change) {
4024             syncingSelection = true;
4025             if (lastModelSelection != null) {
4026                 restoreSortingSelection(lastModelSelection,
4027                                         modelLeadIndex, change);
4028                 lastModelSelection = null;
4029             } else if (modelSelection != null) {
4030                 ListSelectionModel viewSelection = getSelectionModel();
4031                 viewSelection.setValueIsAdjusting(true);
4032                 viewSelection.clearSelection();
4033                 int min = modelSelection.getMinSelectionIndex();
4034                 int max = modelSelection.getMaxSelectionIndex();
4035                 int viewIndex;
4036                 for (int modelIndex = min; modelIndex <= max; modelIndex++) {
4037                     if (modelSelection.isSelectedIndex(modelIndex)) {
4038                         viewIndex = convertRowIndexToView(modelIndex);
4039                         if (viewIndex != -1) {
4040                             viewSelection.addSelectionInterval(viewIndex,
4041                                                                viewIndex);
4042                         }
4043                     }
4044                 }
4045                 // Restore the lead
4046                 int viewLeadIndex = modelSelection.getLeadSelectionIndex();
4047                 if (viewLeadIndex != -1) {
4048                     viewLeadIndex = convertRowIndexToView(viewLeadIndex);
4049                 }
4050                 SwingUtilities2.setLeadAnchorWithoutSelection(
4051                         viewSelection, viewLeadIndex, viewLeadIndex);
4052                 viewSelection.setValueIsAdjusting(false);
4053             }
4054             syncingSelection = false;
4055         }
4056     }
4057 
4058 
4059     /**
4060      * ModelChange is used when sorting to restore state, it corresponds
4061      * to data from a TableModelEvent.  The values are precalculated as
4062      * they are used extensively.
4063      */
4064     private final class ModelChange {
4065         // Starting index of the change, in terms of the model
4066         int startModelIndex;
4067 
4068         // Ending index of the change, in terms of the model
4069         int endModelIndex;
4070 
4071         // Type of change
4072         int type;
4073 
4074         // Number of rows in the model
4075         int modelRowCount;
4076 
4077         // The event that triggered this.
4078         TableModelEvent event;
4079 
4080         // Length of the change (end - start + 1)
4081         int length;
4082 
4083         // True if the event indicates all the contents have changed
4084         boolean allRowsChanged;
4085 
4086         ModelChange(TableModelEvent e) {
4087             startModelIndex = Math.max(0, e.getFirstRow());
4088             endModelIndex = e.getLastRow();
4089             modelRowCount = getModel().getRowCount();
4090             if (endModelIndex < 0) {
4091                 endModelIndex = Math.max(0, modelRowCount - 1);
4092             }
4093             length = endModelIndex - startModelIndex + 1;
4094             type = e.getType();
4095             event = e;
4096             allRowsChanged = (e.getLastRow() == Integer.MAX_VALUE);
4097         }
4098     }
4099 
4100     /**
4101      * Invoked when <code>sorterChanged</code> is invoked, or
4102      * when <code>tableChanged</code> is invoked and sorting is enabled.
4103      */
4104     private void sortedTableChanged(RowSorterEvent sortedEvent,
4105                                     TableModelEvent e) {
4106         int editingModelIndex = -1;
4107         ModelChange change = (e != null) ? new ModelChange(e) : null;
4108 
4109         if ((change == null || !change.allRowsChanged) &&
4110                 this.editingRow != -1) {
4111             editingModelIndex = convertRowIndexToModel(sortedEvent,
4112                                                        this.editingRow);
4113         }
4114 
4115         sortManager.prepareForChange(sortedEvent, change);
4116 
4117         if (e != null) {
4118             if (change.type == TableModelEvent.UPDATE) {
4119                 repaintSortedRows(change);
4120             }
4121             notifySorter(change);
4122             if (change.type != TableModelEvent.UPDATE) {
4123                 // If the Sorter is unsorted we will not have received
4124                 // notification, force treating insert/delete as a change.
4125                 sorterChanged = true;
4126             }
4127         }
4128         else {
4129             sorterChanged = true;
4130         }
4131 
4132         sortManager.processChange(sortedEvent, change, sorterChanged);
4133 
4134         if (sorterChanged) {
4135             // Update the editing row
4136             if (this.editingRow != -1) {
4137                 int newIndex = (editingModelIndex == -1) ? -1 :
4138                         convertRowIndexToView(editingModelIndex,change);
4139                 restoreSortingEditingRow(newIndex);
4140             }
4141 
4142             // And handle the appropriate repainting.
4143             if (e == null || change.type != TableModelEvent.UPDATE) {
4144                 resizeAndRepaint();
4145             }
4146         }
4147 
4148         // Check if lead/anchor need to be reset.
4149         if (change != null && change.allRowsChanged) {
4150             clearSelectionAndLeadAnchor();
4151             resizeAndRepaint();
4152         }
4153     }
4154 
4155     /**
4156      * Repaints the sort of sorted rows in response to a TableModelEvent.
4157      */
4158     private void repaintSortedRows(ModelChange change) {
4159         if (change.startModelIndex > change.endModelIndex ||
4160                 change.startModelIndex + 10 < change.endModelIndex) {
4161             // Too much has changed, punt
4162             repaint();
4163             return;
4164         }
4165         int eventColumn = change.event.getColumn();
4166         int columnViewIndex = eventColumn;
4167         if (columnViewIndex == TableModelEvent.ALL_COLUMNS) {
4168             columnViewIndex = 0;
4169         }
4170         else {
4171             columnViewIndex = convertColumnIndexToView(columnViewIndex);
4172             if (columnViewIndex == -1) {
4173                 return;
4174             }
4175         }
4176         int modelIndex = change.startModelIndex;
4177         while (modelIndex <= change.endModelIndex) {
4178             int viewIndex = convertRowIndexToView(modelIndex++);
4179             if (viewIndex != -1) {
4180                 Rectangle dirty = getCellRect(viewIndex, columnViewIndex,
4181                                               false);
4182                 int x = dirty.x;
4183                 int w = dirty.width;
4184                 if (eventColumn == TableModelEvent.ALL_COLUMNS) {
4185                     x = 0;
4186                     w = getWidth();
4187                 }
4188                 repaint(x, dirty.y, w, dirty.height);
4189             }
4190         }
4191     }
4192 
4193     /**
4194      * Restores the selection after a model event/sort order changes.
4195      * All coordinates are in terms of the model.
4196      */
4197     private void restoreSortingSelection(int[] selection, int lead,
4198             ModelChange change) {
4199         // Convert the selection from model to view
4200         for (int i = selection.length - 1; i >= 0; i--) {
4201             selection[i] = convertRowIndexToView(selection[i], change);
4202         }
4203         lead = convertRowIndexToView(lead, change);
4204 
4205         // Check for the common case of no change in selection for 1 row
4206         if (selection.length == 0 ||
4207             (selection.length == 1 && selection[0] == getSelectedRow())) {
4208             return;
4209         }
4210 
4211         // And apply the new selection
4212         selectionModel.setValueIsAdjusting(true);
4213         selectionModel.clearSelection();
4214         for (int i = selection.length - 1; i >= 0; i--) {
4215             if (selection[i] != -1) {
4216                 selectionModel.addSelectionInterval(selection[i],
4217                                                     selection[i]);
4218             }
4219         }
4220         SwingUtilities2.setLeadAnchorWithoutSelection(
4221                 selectionModel, lead, lead);
4222         selectionModel.setValueIsAdjusting(false);
4223     }
4224 
4225     /**
4226      * Restores the editing row after a model event/sort order change.
4227      *
4228      * @param editingRow new index of the editingRow, in terms of the view
4229      */
4230     private void restoreSortingEditingRow(int editingRow) {
4231         if (editingRow == -1) {
4232             // Editing row no longer being shown, cancel editing
4233             TableCellEditor editor = getCellEditor();
4234             if (editor != null) {
4235                 // First try and cancel
4236                 editor.cancelCellEditing();
4237                 if (getCellEditor() != null) {
4238                     // CellEditor didn't cede control, forcefully
4239                     // remove it
4240                     removeEditor();
4241                 }
4242             }
4243         }
4244         else {
4245             // Repositioning handled in BasicTableUI
4246             this.editingRow = editingRow;
4247             repaint();
4248         }
4249     }
4250 
4251     /**
4252      * Notifies the sorter of a change in the underlying model.
4253      */
4254     private void notifySorter(ModelChange change) {
4255         try {
4256             ignoreSortChange = true;
4257             sorterChanged = false;
4258             switch(change.type) {
4259             case TableModelEvent.UPDATE:
4260                 if (change.event.getLastRow() == Integer.MAX_VALUE) {
4261                     sortManager.sorter.allRowsChanged();
4262                 } else if (change.event.getColumn() ==
4263                            TableModelEvent.ALL_COLUMNS) {
4264                     sortManager.sorter.rowsUpdated(change.startModelIndex,
4265                                        change.endModelIndex);
4266                 } else {
4267                     sortManager.sorter.rowsUpdated(change.startModelIndex,
4268                                        change.endModelIndex,
4269                                        change.event.getColumn());
4270                 }
4271                 break;
4272             case TableModelEvent.INSERT:
4273                 sortManager.sorter.rowsInserted(change.startModelIndex,
4274                                     change.endModelIndex);
4275                 break;
4276             case TableModelEvent.DELETE:
4277                 sortManager.sorter.rowsDeleted(change.startModelIndex,
4278                                    change.endModelIndex);
4279                 break;
4280             }
4281         } finally {
4282             ignoreSortChange = false;
4283         }
4284     }
4285 
4286     /**
4287      * Converts a model index to view index.  This is called when the
4288      * sorter or model changes and sorting is enabled.
4289      *
4290      * @param change describes the TableModelEvent that initiated the change;
4291      *        will be null if called as the result of a sort
4292      */
4293     private int convertRowIndexToView(int modelIndex, ModelChange change) {
4294         if (modelIndex < 0) {
4295             return -1;
4296         }
4297         if (change != null && modelIndex >= change.startModelIndex) {
4298             if (change.type == TableModelEvent.INSERT) {
4299                 if (modelIndex + change.length >= change.modelRowCount) {
4300                     return -1;
4301                 }
4302                 return sortManager.sorter.convertRowIndexToView(
4303                         modelIndex + change.length);
4304             }
4305             else if (change.type == TableModelEvent.DELETE) {
4306                 if (modelIndex <= change.endModelIndex) {
4307                     // deleted
4308                     return -1;
4309                 }
4310                 else {
4311                     if (modelIndex - change.length >= change.modelRowCount) {
4312                         return -1;
4313                     }
4314                     return sortManager.sorter.convertRowIndexToView(
4315                             modelIndex - change.length);
4316                 }
4317             }
4318             // else, updated
4319         }
4320         if (modelIndex >= getModel().getRowCount()) {
4321             return -1;
4322         }
4323         return sortManager.sorter.convertRowIndexToView(modelIndex);
4324     }
4325 
4326     /**
4327      * Converts the selection to model coordinates.  This is used when
4328      * the model changes or the sorter changes.
4329      */
4330     private int[] convertSelectionToModel(RowSorterEvent e) {
4331         int[] selection = getSelectedRows();
4332         for (int i = selection.length - 1; i >= 0; i--) {
4333             selection[i] = convertRowIndexToModel(e, selection[i]);
4334         }
4335         return selection;
4336     }
4337 
4338     private int convertRowIndexToModel(RowSorterEvent e, int viewIndex) {
4339         if (e != null) {
4340             if (e.getPreviousRowCount() == 0) {
4341                 return viewIndex;
4342             }
4343             // range checking handled by RowSorterEvent
4344             return e.convertPreviousRowIndexToModel(viewIndex);
4345         }
4346         // Make sure the viewIndex is valid
4347         if (viewIndex < 0 || viewIndex >= getRowCount()) {
4348             return -1;
4349         }
4350         return convertRowIndexToModel(viewIndex);
4351     }
4352 
4353 //
4354 // Implementing TableModelListener interface
4355 //
4356 
4357     /**
4358      * Invoked when this table's <code>TableModel</code> generates
4359      * a <code>TableModelEvent</code>.
4360      * The <code>TableModelEvent</code> should be constructed in the
4361      * coordinate system of the model; the appropriate mapping to the
4362      * view coordinate system is performed by this <code>JTable</code>
4363      * when it receives the event.
4364      * <p>
4365      * Application code will not use these methods explicitly, they
4366      * are used internally by <code>JTable</code>.
4367      * <p>
4368      * Note that as of 1.3, this method clears the selection, if any.
4369      */
4370     public void tableChanged(TableModelEvent e) {
4371         if (e == null || e.getFirstRow() == TableModelEvent.HEADER_ROW) {
4372             // The whole thing changed
4373             clearSelectionAndLeadAnchor();
4374 
4375             rowModel = null;
4376 
4377             if (sortManager != null) {
4378                 try {
4379                     ignoreSortChange = true;
4380                     sortManager.sorter.modelStructureChanged();
4381                 } finally {
4382                     ignoreSortChange = false;
4383                 }
4384                 sortManager.allChanged();
4385             }
4386 
4387             if (getAutoCreateColumnsFromModel()) {
4388                 // This will effect invalidation of the JTable and JTableHeader.
4389                 createDefaultColumnsFromModel();
4390                 return;
4391             }
4392 
4393             resizeAndRepaint();
4394             return;
4395         }
4396 
4397         if (sortManager != null) {
4398             sortedTableChanged(null, e);
4399             return;
4400         }
4401 
4402         // The totalRowHeight calculated below will be incorrect if
4403         // there are variable height rows. Repaint the visible region,
4404         // but don't return as a revalidate may be necessary as well.
4405         if (rowModel != null) {
4406             repaint();
4407         }
4408 
4409         if (e.getType() == TableModelEvent.INSERT) {
4410             tableRowsInserted(e);
4411             return;
4412         }
4413 
4414         if (e.getType() == TableModelEvent.DELETE) {
4415             tableRowsDeleted(e);
4416             return;
4417         }
4418 
4419         int modelColumn = e.getColumn();
4420         int start = e.getFirstRow();
4421         int end = e.getLastRow();
4422 
4423         Rectangle dirtyRegion;
4424         if (modelColumn == TableModelEvent.ALL_COLUMNS) {
4425             // 1 or more rows changed
4426             dirtyRegion = new Rectangle(0, start * getRowHeight(),
4427                                         getColumnModel().getTotalColumnWidth(), 0);
4428         }
4429         else {
4430             // A cell or column of cells has changed.
4431             // Unlike the rest of the methods in the JTable, the TableModelEvent
4432             // uses the coordinate system of the model instead of the view.
4433             // This is the only place in the JTable where this "reverse mapping"
4434             // is used.
4435             int column = convertColumnIndexToView(modelColumn);
4436             dirtyRegion = getCellRect(start, column, false);
4437         }
4438 
4439         // Now adjust the height of the dirty region according to the value of "end".
4440         // Check for Integer.MAX_VALUE as this will cause an overflow.
4441         if (end != Integer.MAX_VALUE) {
4442             dirtyRegion.height = (end-start+1)*getRowHeight();
4443             repaint(dirtyRegion.x, dirtyRegion.y, dirtyRegion.width, dirtyRegion.height);
4444         }
4445         // In fact, if the end is Integer.MAX_VALUE we need to revalidate anyway
4446         // because the scrollbar may need repainting.
4447         else {
4448             clearSelectionAndLeadAnchor();
4449             resizeAndRepaint();
4450             rowModel = null;
4451         }
4452     }
4453 
4454     /*
4455      * Invoked when rows have been inserted into the table.
4456      * <p>
4457      * Application code will not use these methods explicitly, they
4458      * are used internally by JTable.
4459      *
4460      * @param e the TableModelEvent encapsulating the insertion
4461      */
4462     private void tableRowsInserted(TableModelEvent e) {
4463         int start = e.getFirstRow();
4464         int end = e.getLastRow();
4465         if (start < 0) {
4466             start = 0;
4467         }
4468         if (end < 0) {
4469             end = getRowCount()-1;
4470         }
4471 
4472         // Adjust the selection to account for the new rows.
4473         int length = end - start + 1;
4474         selectionModel.insertIndexInterval(start, length, true);
4475 
4476         // If we have variable height rows, adjust the row model.
4477         if (rowModel != null) {
4478             rowModel.insertEntries(start, length, getRowHeight());
4479         }
4480         int rh = getRowHeight() ;
4481         Rectangle drawRect = new Rectangle(0, start * rh,
4482                                         getColumnModel().getTotalColumnWidth(),
4483                                            (getRowCount()-start) * rh);
4484 
4485         revalidate();
4486         // PENDING(milne) revalidate calls repaint() if parent is a ScrollPane
4487         // repaint still required in the unusual case where there is no ScrollPane
4488         repaint(drawRect);
4489     }
4490 
4491     /*
4492      * Invoked when rows have been removed from the table.
4493      * <p>
4494      * Application code will not use these methods explicitly, they
4495      * are used internally by JTable.
4496      *
4497      * @param e the TableModelEvent encapsulating the deletion
4498      */
4499     private void tableRowsDeleted(TableModelEvent e) {
4500         int start = e.getFirstRow();
4501         int end = e.getLastRow();
4502         if (start < 0) {
4503             start = 0;
4504         }
4505         if (end < 0) {
4506             end = getRowCount()-1;
4507         }
4508 
4509         int deletedCount = end - start + 1;
4510         int previousRowCount = getRowCount() + deletedCount;
4511         // Adjust the selection to account for the new rows
4512         selectionModel.removeIndexInterval(start, end);
4513 
4514         // If we have variable height rows, adjust the row model.
4515         if (rowModel != null) {
4516             rowModel.removeEntries(start, deletedCount);
4517         }
4518 
4519         int rh = getRowHeight();
4520         Rectangle drawRect = new Rectangle(0, start * rh,
4521                                         getColumnModel().getTotalColumnWidth(),
4522                                         (previousRowCount - start) * rh);
4523 
4524         revalidate();
4525         // PENDING(milne) revalidate calls repaint() if parent is a ScrollPane
4526         // repaint still required in the unusual case where there is no ScrollPane
4527         repaint(drawRect);
4528     }
4529 
4530 //
4531 // Implementing TableColumnModelListener interface
4532 //
4533 
4534     /**
4535      * Invoked when a column is added to the table column model.
4536      * <p>
4537      * Application code will not use these methods explicitly, they
4538      * are used internally by JTable.
4539      *
4540      * @see TableColumnModelListener
4541      */
4542     public void columnAdded(TableColumnModelEvent e) {
4543         // If I'm currently editing, then I should stop editing
4544         if (isEditing()) {
4545             removeEditor();
4546         }
4547         resizeAndRepaint();
4548     }
4549 
4550     /**
4551      * Invoked when a column is removed from the table column model.
4552      * <p>
4553      * Application code will not use these methods explicitly, they
4554      * are used internally by JTable.
4555      *
4556      * @see TableColumnModelListener
4557      */
4558     public void columnRemoved(TableColumnModelEvent e) {
4559         // If I'm currently editing, then I should stop editing
4560         if (isEditing()) {
4561             removeEditor();
4562         }
4563         resizeAndRepaint();
4564     }
4565 
4566     /**
4567      * Invoked when a column is repositioned. If a cell is being
4568      * edited, then editing is stopped and the cell is redrawn.
4569      * <p>
4570      * Application code will not use these methods explicitly, they
4571      * are used internally by JTable.
4572      *
4573      * @param e   the event received
4574      * @see TableColumnModelListener
4575      */
4576     public void columnMoved(TableColumnModelEvent e) {
4577         if (isEditing() && !getCellEditor().stopCellEditing()) {
4578             getCellEditor().cancelCellEditing();
4579         }
4580         repaint();
4581     }
4582 
4583     /**
4584      * Invoked when a column is moved due to a margin change.
4585      * If a cell is being edited, then editing is stopped and the cell
4586      * is redrawn.
4587      * <p>
4588      * Application code will not use these methods explicitly, they
4589      * are used internally by JTable.
4590      *
4591      * @param  e    the event received
4592      * @see TableColumnModelListener
4593      */
4594     public void columnMarginChanged(ChangeEvent e) {
4595         if (isEditing() && !getCellEditor().stopCellEditing()) {
4596             getCellEditor().cancelCellEditing();
4597         }
4598         TableColumn resizingColumn = getResizingColumn();
4599         // Need to do this here, before the parent's
4600         // layout manager calls getPreferredSize().
4601         if (resizingColumn != null && autoResizeMode == AUTO_RESIZE_OFF) {
4602             resizingColumn.setPreferredWidth(resizingColumn.getWidth());
4603         }
4604         resizeAndRepaint();
4605     }
4606 
4607     private int limit(int i, int a, int b) {
4608         return Math.min(b, Math.max(i, a));
4609     }
4610 
4611     /**
4612      * Invoked when the selection model of the <code>TableColumnModel</code>
4613      * is changed.
4614      * <p>
4615      * Application code will not use these methods explicitly, they
4616      * are used internally by JTable.
4617      *
4618      * @param  e  the event received
4619      * @see TableColumnModelListener
4620      */
4621     public void columnSelectionChanged(ListSelectionEvent e) {
4622         boolean isAdjusting = e.getValueIsAdjusting();
4623         if (columnSelectionAdjusting && !isAdjusting) {
4624             // The assumption is that when the model is no longer adjusting
4625             // we will have already gotten all the changes, and therefore
4626             // don't need to do an additional paint.
4627             columnSelectionAdjusting = false;
4628             return;
4629         }
4630         columnSelectionAdjusting = isAdjusting;
4631         // The getCellRect() call will fail unless there is at least one row.
4632         if (getRowCount() <= 0 || getColumnCount() <= 0) {
4633             return;
4634         }
4635         int firstIndex = limit(e.getFirstIndex(), 0, getColumnCount()-1);
4636         int lastIndex = limit(e.getLastIndex(), 0, getColumnCount()-1);
4637         int minRow = 0;
4638         int maxRow = getRowCount() - 1;
4639         if (getRowSelectionAllowed()) {
4640             minRow = selectionModel.getMinSelectionIndex();
4641             maxRow = selectionModel.getMaxSelectionIndex();
4642             int leadRow = getAdjustedIndex(selectionModel.getLeadSelectionIndex(), true);
4643 
4644             if (minRow == -1 || maxRow == -1) {
4645                 if (leadRow == -1) {
4646                     // nothing to repaint, return
4647                     return;
4648                 }
4649 
4650                 // only thing to repaint is the lead
4651                 minRow = maxRow = leadRow;
4652             } else {
4653                 // We need to consider more than just the range between
4654                 // the min and max selected index. The lead row, which could
4655                 // be outside this range, should be considered also.
4656                 if (leadRow != -1) {
4657                     minRow = Math.min(minRow, leadRow);
4658                     maxRow = Math.max(maxRow, leadRow);
4659                 }
4660             }
4661         }
4662         Rectangle firstColumnRect = getCellRect(minRow, firstIndex, false);
4663         Rectangle lastColumnRect = getCellRect(maxRow, lastIndex, false);
4664         Rectangle dirtyRegion = firstColumnRect.union(lastColumnRect);
4665         repaint(dirtyRegion);
4666     }
4667 
4668 //
4669 // Implementing ListSelectionListener interface
4670 //
4671 
4672     /**
4673      * Invoked when the row selection changes -- repaints to show the new
4674      * selection.
4675      * <p>
4676      * Application code will not use these methods explicitly, they
4677      * are used internally by JTable.
4678      *
4679      * @param e   the event received
4680      * @see ListSelectionListener
4681      */
4682     public void valueChanged(ListSelectionEvent e) {
4683         if (sortManager != null) {
4684             sortManager.viewSelectionChanged(e);
4685         }
4686         boolean isAdjusting = e.getValueIsAdjusting();
4687         if (rowSelectionAdjusting && !isAdjusting) {
4688             // The assumption is that when the model is no longer adjusting
4689             // we will have already gotten all the changes, and therefore
4690             // don't need to do an additional paint.
4691             rowSelectionAdjusting = false;
4692             return;
4693         }
4694         rowSelectionAdjusting = isAdjusting;
4695         // The getCellRect() calls will fail unless there is at least one column.
4696         if (getRowCount() <= 0 || getColumnCount() <= 0) {
4697             return;
4698         }
4699         int firstIndex = limit(e.getFirstIndex(), 0, getRowCount()-1);
4700         int lastIndex = limit(e.getLastIndex(), 0, getRowCount()-1);
4701         Rectangle firstRowRect = getCellRect(firstIndex, 0, false);
4702         Rectangle lastRowRect = getCellRect(lastIndex, getColumnCount()-1, false);
4703         Rectangle dirtyRegion = firstRowRect.union(lastRowRect);
4704         repaint(dirtyRegion);
4705     }
4706 
4707 //
4708 // Implementing the CellEditorListener interface
4709 //
4710 
4711     /**
4712      * Invoked when editing is finished. The changes are saved and the
4713      * editor is discarded.
4714      * <p>
4715      * Application code will not use these methods explicitly, they
4716      * are used internally by JTable.
4717      *
4718      * @param  e  the event received
4719      * @see CellEditorListener
4720      */
4721     public void editingStopped(ChangeEvent e) {
4722         // Take in the new value
4723         TableCellEditor editor = getCellEditor();
4724         if (editor != null) {
4725             Object value = editor.getCellEditorValue();
4726             setValueAt(value, editingRow, editingColumn);
4727             removeEditor();
4728         }
4729     }
4730 
4731     /**
4732      * Invoked when editing is canceled. The editor object is discarded
4733      * and the cell is rendered once again.
4734      * <p>
4735      * Application code will not use these methods explicitly, they
4736      * are used internally by JTable.
4737      *
4738      * @param  e  the event received
4739      * @see CellEditorListener
4740      */
4741     public void editingCanceled(ChangeEvent e) {
4742         removeEditor();
4743     }
4744 
4745 //
4746 // Implementing the Scrollable interface
4747 //
4748 
4749     /**
4750      * Sets the preferred size of the viewport for this table.
4751      *
4752      * @param size  a <code>Dimension</code> object specifying the <code>preferredSize</code> of a
4753      *              <code>JViewport</code> whose view is this table
4754      * @see Scrollable#getPreferredScrollableViewportSize
4755      * @beaninfo
4756      * description: The preferred size of the viewport.
4757      */
4758     public void setPreferredScrollableViewportSize(Dimension size) {
4759         preferredViewportSize = size;
4760     }
4761 
4762     /**
4763      * Returns the preferred size of the viewport for this table.
4764      *
4765      * @return a <code>Dimension</code> object containing the <code>preferredSize</code> of the <code>JViewport</code>
4766      *         which displays this table
4767      * @see Scrollable#getPreferredScrollableViewportSize
4768      */
4769     public Dimension getPreferredScrollableViewportSize() {
4770         return preferredViewportSize;
4771     }
4772 
4773     /**
4774      * Returns the scroll increment (in pixels) that completely exposes one new
4775      * row or column (depending on the orientation).
4776      * <p>
4777      * This method is called each time the user requests a unit scroll.
4778      *
4779      * @param visibleRect the view area visible within the viewport
4780      * @param orientation either <code>SwingConstants.VERTICAL</code>
4781      *                  or <code>SwingConstants.HORIZONTAL</code>
4782      * @param direction less than zero to scroll up/left,
4783      *                  greater than zero for down/right
4784      * @return the "unit" increment for scrolling in the specified direction
4785      * @see Scrollable#getScrollableUnitIncrement
4786      */
4787     public int getScrollableUnitIncrement(Rectangle visibleRect,
4788                                           int orientation,
4789                                           int direction) {
4790         int leadingRow;
4791         int leadingCol;
4792         Rectangle leadingCellRect;
4793 
4794         int leadingVisibleEdge;
4795         int leadingCellEdge;
4796         int leadingCellSize;
4797 
4798         leadingRow = getLeadingRow(visibleRect);
4799         leadingCol = getLeadingCol(visibleRect);
4800         if (orientation == SwingConstants.VERTICAL && leadingRow < 0) {
4801             // Couldn't find leading row - return some default value
4802             return getRowHeight();
4803         }
4804         else if (orientation == SwingConstants.HORIZONTAL && leadingCol < 0) {
4805             // Couldn't find leading col - return some default value
4806             return 100;
4807         }
4808 
4809         // Note that it's possible for one of leadingCol or leadingRow to be
4810         // -1, depending on the orientation.  This is okay, as getCellRect()
4811         // still provides enough information to calculate the unit increment.
4812         leadingCellRect = getCellRect(leadingRow, leadingCol, true);
4813         leadingVisibleEdge = leadingEdge(visibleRect, orientation);
4814         leadingCellEdge = leadingEdge(leadingCellRect, orientation);
4815 
4816         if (orientation == SwingConstants.VERTICAL) {
4817             leadingCellSize = leadingCellRect.height;
4818 
4819         }
4820         else {
4821             leadingCellSize = leadingCellRect.width;
4822         }
4823 
4824         // 4 cases:
4825         // #1: Leading cell fully visible, reveal next cell
4826         // #2: Leading cell fully visible, hide leading cell
4827         // #3: Leading cell partially visible, hide rest of leading cell
4828         // #4: Leading cell partially visible, reveal rest of leading cell
4829 
4830         if (leadingVisibleEdge == leadingCellEdge) { // Leading cell is fully
4831                                                      // visible
4832             // Case #1: Reveal previous cell
4833             if (direction < 0) {
4834                 int retVal = 0;
4835 
4836                 if (orientation == SwingConstants.VERTICAL) {
4837                     // Loop past any zero-height rows
4838                     while (--leadingRow >= 0) {
4839                         retVal = getRowHeight(leadingRow);
4840                         if (retVal != 0) {
4841                             break;
4842                         }
4843                     }
4844                 }
4845                 else { // HORIZONTAL
4846                     // Loop past any zero-width cols
4847                     while (--leadingCol >= 0) {
4848                         retVal = getCellRect(leadingRow, leadingCol, true).width;
4849                         if (retVal != 0) {
4850                             break;
4851                         }
4852                     }
4853                 }
4854                 return retVal;
4855             }
4856             else { // Case #2: hide leading cell
4857                 return leadingCellSize;
4858             }
4859         }
4860         else { // Leading cell is partially hidden
4861             // Compute visible, hidden portions
4862             int hiddenAmt = Math.abs(leadingVisibleEdge - leadingCellEdge);
4863             int visibleAmt = leadingCellSize - hiddenAmt;
4864 
4865             if (direction > 0) {
4866                 // Case #3: hide showing portion of leading cell
4867                 return visibleAmt;
4868             }
4869             else { // Case #4: reveal hidden portion of leading cell
4870                 return hiddenAmt;
4871             }
4872         }
4873     }
4874 
4875     /**
4876      * Returns <code>visibleRect.height</code> or
4877      * <code>visibleRect.width</code>,
4878      * depending on this table's orientation.  Note that as of Swing 1.1.1
4879      * (Java 2 v 1.2.2) the value
4880      * returned will ensure that the viewport is cleanly aligned on
4881      * a row boundary.
4882      *
4883      * @return <code>visibleRect.height</code> or
4884      *                                  <code>visibleRect.width</code>
4885      *                                  per the orientation
4886      * @see Scrollable#getScrollableBlockIncrement
4887      */
4888     public int getScrollableBlockIncrement(Rectangle visibleRect,
4889             int orientation, int direction) {
4890 
4891         if (getRowCount() == 0) {
4892             // Short-circuit empty table model
4893             if (SwingConstants.VERTICAL == orientation) {
4894                 int rh = getRowHeight();
4895                 return (rh > 0) ? Math.max(rh, (visibleRect.height / rh) * rh) :
4896                                   visibleRect.height;
4897             }
4898             else {
4899                 return visibleRect.width;
4900             }
4901         }
4902         // Shortcut for vertical scrolling of a table w/ uniform row height
4903         if (null == rowModel && SwingConstants.VERTICAL == orientation) {
4904             int row = rowAtPoint(visibleRect.getLocation());
4905             assert row != -1;
4906             int col = columnAtPoint(visibleRect.getLocation());
4907             Rectangle cellRect = getCellRect(row, col, true);
4908 
4909             if (cellRect.y == visibleRect.y) {
4910                 int rh = getRowHeight();
4911                 assert rh > 0;
4912                 return Math.max(rh, (visibleRect.height / rh) * rh);
4913             }
4914         }
4915         if (direction < 0) {
4916             return getPreviousBlockIncrement(visibleRect, orientation);
4917         }
4918         else {
4919             return getNextBlockIncrement(visibleRect, orientation);
4920         }
4921     }
4922 
4923     /**
4924      * Called to get the block increment for upward scrolling in cases of
4925      * horizontal scrolling, or for vertical scrolling of a table with
4926      * variable row heights.
4927      */
4928     private int getPreviousBlockIncrement(Rectangle visibleRect,
4929                                           int orientation) {
4930         // Measure back from visible leading edge
4931         // If we hit the cell on its leading edge, it becomes the leading cell.
4932         // Else, use following cell
4933 
4934         int row;
4935         int col;
4936 
4937         int   newEdge;
4938         Point newCellLoc;
4939 
4940         int visibleLeadingEdge = leadingEdge(visibleRect, orientation);
4941         boolean leftToRight = getComponentOrientation().isLeftToRight();
4942         int newLeadingEdge;
4943 
4944         // Roughly determine the new leading edge by measuring back from the
4945         // leading visible edge by the size of the visible rect, and find the
4946         // cell there.
4947         if (orientation == SwingConstants.VERTICAL) {
4948             newEdge = visibleLeadingEdge - visibleRect.height;
4949             int x = visibleRect.x + (leftToRight ? 0 : visibleRect.width);
4950             newCellLoc = new Point(x, newEdge);
4951         }
4952         else if (leftToRight) {
4953             newEdge = visibleLeadingEdge - visibleRect.width;
4954             newCellLoc = new Point(newEdge, visibleRect.y);
4955         }
4956         else { // Horizontal, right-to-left
4957             newEdge = visibleLeadingEdge + visibleRect.width;
4958             newCellLoc = new Point(newEdge - 1, visibleRect.y);
4959         }
4960         row = rowAtPoint(newCellLoc);
4961         col = columnAtPoint(newCellLoc);
4962 
4963         // If we're measuring past the beginning of the table, we get an invalid
4964         // cell.  Just go to the beginning of the table in this case.
4965         if (orientation == SwingConstants.VERTICAL & row < 0) {
4966             newLeadingEdge = 0;
4967         }
4968         else if (orientation == SwingConstants.HORIZONTAL & col < 0) {
4969             if (leftToRight) {
4970                 newLeadingEdge = 0;
4971             }
4972             else {
4973                 newLeadingEdge = getWidth();
4974             }
4975         }
4976         else {
4977             // Refine our measurement
4978             Rectangle newCellRect = getCellRect(row, col, true);
4979             int newCellLeadingEdge = leadingEdge(newCellRect, orientation);
4980             int newCellTrailingEdge = trailingEdge(newCellRect, orientation);
4981 
4982             // Usually, we hit in the middle of newCell, and want to scroll to
4983             // the beginning of the cell after newCell.  But there are a
4984             // couple corner cases where we want to scroll to the beginning of
4985             // newCell itself.  These cases are:
4986             // 1) newCell is so large that it ends at or extends into the
4987             //    visibleRect (newCell is the leading cell, or is adjacent to
4988             //    the leading cell)
4989             // 2) newEdge happens to fall right on the beginning of a cell
4990 
4991             // Case 1
4992             if ((orientation == SwingConstants.VERTICAL || leftToRight) &&
4993                 (newCellTrailingEdge >= visibleLeadingEdge)) {
4994                 newLeadingEdge = newCellLeadingEdge;
4995             }
4996             else if (orientation == SwingConstants.HORIZONTAL &&
4997                      !leftToRight &&
4998                      newCellTrailingEdge <= visibleLeadingEdge) {
4999                 newLeadingEdge = newCellLeadingEdge;
5000             }
5001             // Case 2:
5002             else if (newEdge == newCellLeadingEdge) {
5003                 newLeadingEdge = newCellLeadingEdge;
5004             }
5005             // Common case: scroll to cell after newCell
5006             else {
5007                 newLeadingEdge = newCellTrailingEdge;
5008             }
5009         }
5010         return Math.abs(visibleLeadingEdge - newLeadingEdge);
5011     }
5012 
5013     /**
5014      * Called to get the block increment for downward scrolling in cases of
5015      * horizontal scrolling, or for vertical scrolling of a table with
5016      * variable row heights.
5017      */
5018     private int getNextBlockIncrement(Rectangle visibleRect,
5019                                       int orientation) {
5020         // Find the cell at the trailing edge.  Return the distance to put
5021         // that cell at the leading edge.
5022         int trailingRow = getTrailingRow(visibleRect);
5023         int trailingCol = getTrailingCol(visibleRect);
5024 
5025         Rectangle cellRect;
5026         boolean cellFillsVis;
5027 
5028         int cellLeadingEdge;
5029         int cellTrailingEdge;
5030         int newLeadingEdge;
5031         int visibleLeadingEdge = leadingEdge(visibleRect, orientation);
5032 
5033         // If we couldn't find trailing cell, just return the size of the
5034         // visibleRect.  Note that, for instance, we don't need the
5035         // trailingCol to proceed if we're scrolling vertically, because
5036         // cellRect will still fill in the required dimensions.  This would
5037         // happen if we're scrolling vertically, and the table is not wide
5038         // enough to fill the visibleRect.
5039         if (orientation == SwingConstants.VERTICAL && trailingRow < 0) {
5040             return visibleRect.height;
5041         }
5042         else if (orientation == SwingConstants.HORIZONTAL && trailingCol < 0) {
5043             return visibleRect.width;
5044         }
5045         cellRect = getCellRect(trailingRow, trailingCol, true);
5046         cellLeadingEdge = leadingEdge(cellRect, orientation);
5047         cellTrailingEdge = trailingEdge(cellRect, orientation);
5048 
5049         if (orientation == SwingConstants.VERTICAL ||
5050             getComponentOrientation().isLeftToRight()) {
5051             cellFillsVis = cellLeadingEdge <= visibleLeadingEdge;
5052         }
5053         else { // Horizontal, right-to-left
5054             cellFillsVis = cellLeadingEdge >= visibleLeadingEdge;
5055         }
5056 
5057         if (cellFillsVis) {
5058             // The visibleRect contains a single large cell.  Scroll to the end
5059             // of this cell, so the following cell is the first cell.
5060             newLeadingEdge = cellTrailingEdge;
5061         }
5062         else if (cellTrailingEdge == trailingEdge(visibleRect, orientation)) {
5063             // The trailing cell happens to end right at the end of the
5064             // visibleRect.  Again, scroll to the beginning of the next cell.
5065             newLeadingEdge = cellTrailingEdge;
5066         }
5067         else {
5068             // Common case: the trailing cell is partially visible, and isn't
5069             // big enough to take up the entire visibleRect.  Scroll so it
5070             // becomes the leading cell.
5071             newLeadingEdge = cellLeadingEdge;
5072         }
5073         return Math.abs(newLeadingEdge - visibleLeadingEdge);
5074     }
5075 
5076     /*
5077      * Return the row at the top of the visibleRect
5078      *
5079      * May return -1
5080      */
5081     private int getLeadingRow(Rectangle visibleRect) {
5082         Point leadingPoint;
5083 
5084         if (getComponentOrientation().isLeftToRight()) {
5085             leadingPoint = new Point(visibleRect.x, visibleRect.y);
5086         }
5087         else {
5088             leadingPoint = new Point(visibleRect.x + visibleRect.width - 1,
5089                                      visibleRect.y);
5090         }
5091         return rowAtPoint(leadingPoint);
5092     }
5093 
5094     /*
5095      * Return the column at the leading edge of the visibleRect.
5096      *
5097      * May return -1
5098      */
5099     private int getLeadingCol(Rectangle visibleRect) {
5100         Point leadingPoint;
5101 
5102         if (getComponentOrientation().isLeftToRight()) {
5103             leadingPoint = new Point(visibleRect.x, visibleRect.y);
5104         }
5105         else {
5106             leadingPoint = new Point(visibleRect.x + visibleRect.width - 1,
5107                                      visibleRect.y);
5108         }
5109         return columnAtPoint(leadingPoint);
5110     }
5111 
5112     /*
5113      * Return the row at the bottom of the visibleRect.
5114      *
5115      * May return -1
5116      */
5117     private int getTrailingRow(Rectangle visibleRect) {
5118         Point trailingPoint;
5119 
5120         if (getComponentOrientation().isLeftToRight()) {
5121             trailingPoint = new Point(visibleRect.x,
5122                                       visibleRect.y + visibleRect.height - 1);
5123         }
5124         else {
5125             trailingPoint = new Point(visibleRect.x + visibleRect.width - 1,
5126                                       visibleRect.y + visibleRect.height - 1);
5127         }
5128         return rowAtPoint(trailingPoint);
5129     }
5130 
5131     /*
5132      * Return the column at the trailing edge of the visibleRect.
5133      *
5134      * May return -1
5135      */
5136     private int getTrailingCol(Rectangle visibleRect) {
5137         Point trailingPoint;
5138 
5139         if (getComponentOrientation().isLeftToRight()) {
5140             trailingPoint = new Point(visibleRect.x + visibleRect.width - 1,
5141                                       visibleRect.y);
5142         }
5143         else {
5144             trailingPoint = new Point(visibleRect.x, visibleRect.y);
5145         }
5146         return columnAtPoint(trailingPoint);
5147     }
5148 
5149     /*
5150      * Returns the leading edge ("beginning") of the given Rectangle.
5151      * For VERTICAL, this is the top, for left-to-right, the left side, and for
5152      * right-to-left, the right side.
5153      */
5154     private int leadingEdge(Rectangle rect, int orientation) {
5155         if (orientation == SwingConstants.VERTICAL) {
5156             return rect.y;
5157         }
5158         else if (getComponentOrientation().isLeftToRight()) {
5159             return rect.x;
5160         }
5161         else { // Horizontal, right-to-left
5162             return rect.x + rect.width;
5163         }
5164     }
5165 
5166     /*
5167      * Returns the trailing edge ("end") of the given Rectangle.
5168      * For VERTICAL, this is the bottom, for left-to-right, the right side, and
5169      * for right-to-left, the left side.
5170      */
5171     private int trailingEdge(Rectangle rect, int orientation) {
5172         if (orientation == SwingConstants.VERTICAL) {
5173             return rect.y + rect.height;
5174         }
5175         else if (getComponentOrientation().isLeftToRight()) {
5176             return rect.x + rect.width;
5177         }
5178         else { // Horizontal, right-to-left
5179             return rect.x;
5180         }
5181     }
5182 
5183     /**
5184      * Returns false if <code>autoResizeMode</code> is set to
5185      * <code>AUTO_RESIZE_OFF</code>, which indicates that the
5186      * width of the viewport does not determine the width
5187      * of the table.  Otherwise returns true.
5188      *
5189      * @return false if <code>autoResizeMode</code> is set
5190      *   to <code>AUTO_RESIZE_OFF</code>, otherwise returns true
5191      * @see Scrollable#getScrollableTracksViewportWidth
5192      */
5193     public boolean getScrollableTracksViewportWidth() {
5194         return !(autoResizeMode == AUTO_RESIZE_OFF);
5195     }
5196 
5197     /**
5198      * Returns {@code false} to indicate that the height of the viewport does
5199      * not determine the height of the table, unless
5200      * {@code getFillsViewportHeight} is {@code true} and the preferred height
5201      * of the table is smaller than the viewport's height.
5202      *
5203      * @return {@code false} unless {@code getFillsViewportHeight} is
5204      *         {@code true} and the table needs to be stretched to fill
5205      *         the viewport
5206      * @see Scrollable#getScrollableTracksViewportHeight
5207      * @see #setFillsViewportHeight
5208      * @see #getFillsViewportHeight
5209      */
5210     public boolean getScrollableTracksViewportHeight() {
5211         Container parent = SwingUtilities.getUnwrappedParent(this);
5212         return getFillsViewportHeight()
5213                && parent instanceof JViewport
5214                && parent.getHeight() > getPreferredSize().height;
5215     }
5216 
5217     /**
5218      * Sets whether or not this table is always made large enough
5219      * to fill the height of an enclosing viewport. If the preferred
5220      * height of the table is smaller than the viewport, then the table
5221      * will be stretched to fill the viewport. In other words, this
5222      * ensures the table is never smaller than the viewport.
5223      * The default for this property is {@code false}.
5224      *
5225      * @param fillsViewportHeight whether or not this table is always
5226      *        made large enough to fill the height of an enclosing
5227      *        viewport
5228      * @see #getFillsViewportHeight
5229      * @see #getScrollableTracksViewportHeight
5230      * @since 1.6
5231      * @beaninfo
5232      *      bound: true
5233      *      description: Whether or not this table is always made large enough
5234      *                   to fill the height of an enclosing viewport
5235      */
5236     public void setFillsViewportHeight(boolean fillsViewportHeight) {
5237         boolean old = this.fillsViewportHeight;
5238         this.fillsViewportHeight = fillsViewportHeight;
5239         resizeAndRepaint();
5240         firePropertyChange("fillsViewportHeight", old, fillsViewportHeight);
5241     }
5242 
5243     /**
5244      * Returns whether or not this table is always made large enough
5245      * to fill the height of an enclosing viewport.
5246      *
5247      * @return whether or not this table is always made large enough
5248      *         to fill the height of an enclosing viewport
5249      * @see #setFillsViewportHeight
5250      * @since 1.6
5251      */
5252     public boolean getFillsViewportHeight() {
5253         return fillsViewportHeight;
5254     }
5255 
5256 //
5257 // Protected Methods
5258 //
5259 
5260     protected boolean processKeyBinding(KeyStroke ks, KeyEvent e,
5261                                         int condition, boolean pressed) {
5262         boolean retValue = super.processKeyBinding(ks, e, condition, pressed);
5263 
5264         // Start editing when a key is typed. UI classes can disable this behavior
5265         // by setting the client property JTable.autoStartsEdit to Boolean.FALSE.
5266         if (!retValue && condition == WHEN_ANCESTOR_OF_FOCUSED_COMPONENT &&
5267             isFocusOwner() &&
5268             !Boolean.FALSE.equals(getClientProperty("JTable.autoStartsEdit"))) {
5269             // We do not have a binding for the event.
5270             Component editorComponent = getEditorComponent();
5271             if (editorComponent == null) {
5272                 // Only attempt to install the editor on a KEY_PRESSED,
5273                 if (e == null || e.getID() != KeyEvent.KEY_PRESSED) {
5274                     return false;
5275                 }
5276                 // Don't start when just a modifier is pressed
5277                 int code = e.getKeyCode();
5278                 if (code == KeyEvent.VK_SHIFT || code == KeyEvent.VK_CONTROL ||
5279                     code == KeyEvent.VK_ALT) {
5280                     return false;
5281                 }
5282                 // Try to install the editor
5283                 int leadRow = getSelectionModel().getLeadSelectionIndex();
5284                 int leadColumn = getColumnModel().getSelectionModel().
5285                                    getLeadSelectionIndex();
5286                 if (leadRow != -1 && leadColumn != -1 && !isEditing()) {
5287                     if (!editCellAt(leadRow, leadColumn, e)) {
5288                         return false;
5289                     }
5290                 }
5291                 editorComponent = getEditorComponent();
5292                 if (editorComponent == null) {
5293                     return false;
5294                 }
5295             }
5296             // If the editorComponent is a JComponent, pass the event to it.
5297             if (editorComponent instanceof JComponent) {
5298                 retValue = ((JComponent)editorComponent).processKeyBinding
5299                                         (ks, e, WHEN_FOCUSED, pressed);
5300                 // If we have started an editor as a result of the user
5301                 // pressing a key and the surrendersFocusOnKeystroke property
5302                 // is true, give the focus to the new editor.
5303                 if (getSurrendersFocusOnKeystroke()) {
5304                     editorComponent.requestFocus();
5305                 }
5306             }
5307         }
5308         return retValue;
5309     }
5310 
5311     private void setLazyValue(Hashtable h, Class c, String s) {
5312         h.put(c, new SwingLazyValue(s));
5313     }
5314 
5315     private void setLazyRenderer(Class c, String s) {
5316         setLazyValue(defaultRenderersByColumnClass, c, s);
5317     }
5318 
5319     /**
5320      * Creates default cell renderers for objects, numbers, doubles, dates,
5321      * booleans, and icons.
5322      * @see javax.swing.table.DefaultTableCellRenderer
5323      *
5324      */
5325     protected void createDefaultRenderers() {
5326         defaultRenderersByColumnClass = new UIDefaults(8, 0.75f);
5327 
5328         // Objects
5329         setLazyRenderer(Object.class, "javax.swing.table.DefaultTableCellRenderer$UIResource");
5330 
5331         // Numbers
5332         setLazyRenderer(Number.class, "javax.swing.JTable$NumberRenderer");
5333 
5334         // Doubles and Floats
5335         setLazyRenderer(Float.class, "javax.swing.JTable$DoubleRenderer");
5336         setLazyRenderer(Double.class, "javax.swing.JTable$DoubleRenderer");
5337 
5338         // Dates
5339         setLazyRenderer(Date.class, "javax.swing.JTable$DateRenderer");
5340 
5341         // Icons and ImageIcons
5342         setLazyRenderer(Icon.class, "javax.swing.JTable$IconRenderer");
5343         setLazyRenderer(ImageIcon.class, "javax.swing.JTable$IconRenderer");
5344 
5345         // Booleans
5346         setLazyRenderer(Boolean.class, "javax.swing.JTable$BooleanRenderer");
5347     }
5348 
5349     /**
5350      * Default Renderers
5351      **/
5352     static class NumberRenderer extends DefaultTableCellRenderer.UIResource {
5353         public NumberRenderer() {
5354             super();
5355             setHorizontalAlignment(JLabel.RIGHT);
5356         }
5357     }
5358 
5359     static class DoubleRenderer extends NumberRenderer {
5360         NumberFormat formatter;
5361         public DoubleRenderer() { super(); }
5362 
5363         public void setValue(Object value) {
5364             if (formatter == null) {
5365                 formatter = NumberFormat.getInstance();
5366             }
5367             setText((value == null) ? "" : formatter.format(value));
5368         }
5369     }
5370 
5371     static class DateRenderer extends DefaultTableCellRenderer.UIResource {
5372         DateFormat formatter;
5373         public DateRenderer() { super(); }
5374 
5375         public void setValue(Object value) {
5376             if (formatter==null) {
5377                 formatter = DateFormat.getDateInstance();
5378             }
5379             setText((value == null) ? "" : formatter.format(value));
5380         }
5381     }
5382 
5383     static class IconRenderer extends DefaultTableCellRenderer.UIResource {
5384         public IconRenderer() {
5385             super();
5386             setHorizontalAlignment(JLabel.CENTER);
5387         }
5388         public void setValue(Object value) { setIcon((value instanceof Icon) ? (Icon)value : null); }
5389     }
5390 
5391 
5392     static class BooleanRenderer extends JCheckBox implements TableCellRenderer, UIResource
5393     {
5394         private static final Border noFocusBorder = new EmptyBorder(1, 1, 1, 1);
5395 
5396         public BooleanRenderer() {
5397             super();
5398             setHorizontalAlignment(JLabel.CENTER);
5399             setBorderPainted(true);
5400         }
5401 
5402         public Component getTableCellRendererComponent(JTable table, Object value,
5403                                                        boolean isSelected, boolean hasFocus, int row, int column) {
5404             if (isSelected) {
5405                 setForeground(table.getSelectionForeground());
5406                 super.setBackground(table.getSelectionBackground());
5407             }
5408             else {
5409                 setForeground(table.getForeground());
5410                 setBackground(table.getBackground());
5411             }
5412             setSelected((value != null && ((Boolean)value).booleanValue()));
5413 
5414             if (hasFocus) {
5415                 setBorder(UIManager.getBorder("Table.focusCellHighlightBorder"));
5416             } else {
5417                 setBorder(noFocusBorder);
5418             }
5419 
5420             return this;
5421         }
5422     }
5423 
5424     private void setLazyEditor(Class c, String s) {
5425         setLazyValue(defaultEditorsByColumnClass, c, s);
5426     }
5427 
5428     /**
5429      * Creates default cell editors for objects, numbers, and boolean values.
5430      * @see DefaultCellEditor
5431      */
5432     protected void createDefaultEditors() {
5433         defaultEditorsByColumnClass = new UIDefaults(3, 0.75f);
5434 
5435         // Objects
5436         setLazyEditor(Object.class, "javax.swing.JTable$GenericEditor");
5437 
5438         // Numbers
5439         setLazyEditor(Number.class, "javax.swing.JTable$NumberEditor");
5440 
5441         // Booleans
5442         setLazyEditor(Boolean.class, "javax.swing.JTable$BooleanEditor");
5443     }
5444 
5445     /**
5446      * Default Editors
5447      */
5448     static class GenericEditor extends DefaultCellEditor {
5449 
5450         Class[] argTypes = new Class[]{String.class};
5451         java.lang.reflect.Constructor constructor;
5452         Object value;
5453 
5454         public GenericEditor() {
5455             super(new JTextField());
5456             getComponent().setName("Table.editor");
5457         }
5458 
5459         public boolean stopCellEditing() {
5460             String s = (String)super.getCellEditorValue();
5461             // Here we are dealing with the case where a user
5462             // has deleted the string value in a cell, possibly
5463             // after a failed validation. Return null, so that
5464             // they have the option to replace the value with
5465             // null or use escape to restore the original.
5466             // For Strings, return "" for backward compatibility.
5467             if ("".equals(s)) {
5468                 if (constructor.getDeclaringClass() == String.class) {
5469                     value = s;
5470                 }
5471                 super.stopCellEditing();
5472             }
5473 
5474             try {
5475                 value = constructor.newInstance(new Object[]{s});
5476             }
5477             catch (Exception e) {
5478                 ((JComponent)getComponent()).setBorder(new LineBorder(Color.red));
5479                 return false;
5480             }
5481             return super.stopCellEditing();
5482         }
5483 
5484         public Component getTableCellEditorComponent(JTable table, Object value,
5485                                                  boolean isSelected,
5486                                                  int row, int column) {
5487             this.value = null;
5488             ((JComponent)getComponent()).setBorder(new LineBorder(Color.black));
5489             try {
5490                 Class<?> type = table.getColumnClass(column);
5491                 // Since our obligation is to produce a value which is
5492                 // assignable for the required type it is OK to use the
5493                 // String constructor for columns which are declared
5494                 // to contain Objects. A String is an Object.
5495                 if (type == Object.class) {
5496                     type = String.class;
5497                 }
5498                 constructor = type.getConstructor(argTypes);
5499             }
5500             catch (Exception e) {
5501                 return null;
5502             }
5503             return super.getTableCellEditorComponent(table, value, isSelected, row, column);
5504         }
5505 
5506         public Object getCellEditorValue() {
5507             return value;
5508         }
5509     }
5510 
5511     static class NumberEditor extends GenericEditor {
5512 
5513         public NumberEditor() {
5514             ((JTextField)getComponent()).setHorizontalAlignment(JTextField.RIGHT);
5515         }
5516     }
5517 
5518     static class BooleanEditor extends DefaultCellEditor {
5519         public BooleanEditor() {
5520             super(new JCheckBox());
5521             JCheckBox checkBox = (JCheckBox)getComponent();
5522             checkBox.setHorizontalAlignment(JCheckBox.CENTER);
5523         }
5524     }
5525 
5526     /**
5527      * Initializes table properties to their default values.
5528      */
5529     protected void initializeLocalVars() {
5530         updateSelectionOnSort = true;
5531         setOpaque(true);
5532         createDefaultRenderers();
5533         createDefaultEditors();
5534 
5535         setTableHeader(createDefaultTableHeader());
5536 
5537         setShowGrid(true);
5538         setAutoResizeMode(AUTO_RESIZE_SUBSEQUENT_COLUMNS);
5539         setRowHeight(16);
5540         isRowHeightSet = false;
5541         setRowMargin(1);
5542         setRowSelectionAllowed(true);
5543         setCellEditor(null);
5544         setEditingColumn(-1);
5545         setEditingRow(-1);
5546         setSurrendersFocusOnKeystroke(false);
5547         setPreferredScrollableViewportSize(new Dimension(450, 400));
5548 
5549         // I'm registered to do tool tips so we can draw tips for the renderers
5550         ToolTipManager toolTipManager = ToolTipManager.sharedInstance();
5551         toolTipManager.registerComponent(this);
5552 
5553         setAutoscrolls(true);
5554     }
5555 
5556     /**
5557      * Returns the default table model object, which is
5558      * a <code>DefaultTableModel</code>.  A subclass can override this
5559      * method to return a different table model object.
5560      *
5561      * @return the default table model object
5562      * @see javax.swing.table.DefaultTableModel
5563      */
5564     protected TableModel createDefaultDataModel() {
5565         return new DefaultTableModel();
5566     }
5567 
5568     /**
5569      * Returns the default column model object, which is
5570      * a <code>DefaultTableColumnModel</code>.  A subclass can override this
5571      * method to return a different column model object.
5572      *
5573      * @return the default column model object
5574      * @see javax.swing.table.DefaultTableColumnModel
5575      */
5576     protected TableColumnModel createDefaultColumnModel() {
5577         return new DefaultTableColumnModel();
5578     }
5579 
5580     /**
5581      * Returns the default selection model object, which is
5582      * a <code>DefaultListSelectionModel</code>.  A subclass can override this
5583      * method to return a different selection model object.
5584      *
5585      * @return the default selection model object
5586      * @see javax.swing.DefaultListSelectionModel
5587      */
5588     protected ListSelectionModel createDefaultSelectionModel() {
5589         return new DefaultListSelectionModel();
5590     }
5591 
5592     /**
5593      * Returns the default table header object, which is
5594      * a <code>JTableHeader</code>.  A subclass can override this
5595      * method to return a different table header object.
5596      *
5597      * @return the default table header object
5598      * @see javax.swing.table.JTableHeader
5599      */
5600     protected JTableHeader createDefaultTableHeader() {
5601         return new JTableHeader(columnModel);
5602     }
5603 
5604     /**
5605      * Equivalent to <code>revalidate</code> followed by <code>repaint</code>.
5606      */
5607     protected void resizeAndRepaint() {
5608         revalidate();
5609         repaint();
5610     }
5611 
5612     /**
5613      * Returns the active cell editor, which is {@code null} if the table
5614      * is not currently editing.
5615      *
5616      * @return the {@code TableCellEditor} that does the editing,
5617      *         or {@code null} if the table is not currently editing.
5618      * @see #cellEditor
5619      * @see #getCellEditor(int, int)
5620      */
5621     public TableCellEditor getCellEditor() {
5622         return cellEditor;
5623     }
5624 
5625     /**
5626      * Sets the active cell editor.
5627      *
5628      * @param anEditor the active cell editor
5629      * @see #cellEditor
5630      * @beaninfo
5631      *  bound: true
5632      *  description: The table's active cell editor.
5633      */
5634     public void setCellEditor(TableCellEditor anEditor) {
5635         TableCellEditor oldEditor = cellEditor;
5636         cellEditor = anEditor;
5637         firePropertyChange("tableCellEditor", oldEditor, anEditor);
5638     }
5639 
5640     /**
5641      * Sets the <code>editingColumn</code> variable.
5642      * @param aColumn  the column of the cell to be edited
5643      *
5644      * @see #editingColumn
5645      */
5646     public void setEditingColumn(int aColumn) {
5647         editingColumn = aColumn;
5648     }
5649 
5650     /**
5651      * Sets the <code>editingRow</code> variable.
5652      * @param aRow  the row of the cell to be edited
5653      *
5654      * @see #editingRow
5655      */
5656     public void setEditingRow(int aRow) {
5657         editingRow = aRow;
5658     }
5659 
5660     /**
5661      * Returns an appropriate renderer for the cell specified by this row and
5662      * column. If the <code>TableColumn</code> for this column has a non-null
5663      * renderer, returns that.  If not, finds the class of the data in
5664      * this column (using <code>getColumnClass</code>)
5665      * and returns the default renderer for this type of data.
5666      * <p>
5667      * <b>Note:</b>
5668      * Throughout the table package, the internal implementations always
5669      * use this method to provide renderers so that this default behavior
5670      * can be safely overridden by a subclass.
5671      *
5672      * @param row       the row of the cell to render, where 0 is the first row
5673      * @param column    the column of the cell to render,
5674      *                  where 0 is the first column
5675      * @return the assigned renderer; if <code>null</code>
5676      *                  returns the default renderer
5677      *                  for this type of object
5678      * @see javax.swing.table.DefaultTableCellRenderer
5679      * @see javax.swing.table.TableColumn#setCellRenderer
5680      * @see #setDefaultRenderer
5681      */
5682     public TableCellRenderer getCellRenderer(int row, int column) {
5683         TableColumn tableColumn = getColumnModel().getColumn(column);
5684         TableCellRenderer renderer = tableColumn.getCellRenderer();
5685         if (renderer == null) {
5686             renderer = getDefaultRenderer(getColumnClass(column));
5687         }
5688         return renderer;
5689     }
5690 
5691     /**
5692      * Prepares the renderer by querying the data model for the
5693      * value and selection state
5694      * of the cell at <code>row</code>, <code>column</code>.
5695      * Returns the component (may be a <code>Component</code>
5696      * or a <code>JComponent</code>) under the event location.
5697      * <p>
5698      * During a printing operation, this method will configure the
5699      * renderer without indicating selection or focus, to prevent
5700      * them from appearing in the printed output. To do other
5701      * customizations based on whether or not the table is being
5702      * printed, you can check the value of
5703      * {@link javax.swing.JComponent#isPaintingForPrint()}, either here
5704      * or within custom renderers.
5705      * <p>
5706      * <b>Note:</b>
5707      * Throughout the table package, the internal implementations always
5708      * use this method to prepare renderers so that this default behavior
5709      * can be safely overridden by a subclass.
5710      *
5711      * @param renderer  the <code>TableCellRenderer</code> to prepare
5712      * @param row       the row of the cell to render, where 0 is the first row
5713      * @param column    the column of the cell to render,
5714      *                  where 0 is the first column
5715      * @return          the <code>Component</code> under the event location
5716      */
5717     public Component prepareRenderer(TableCellRenderer renderer, int row, int column) {
5718         Object value = getValueAt(row, column);
5719 
5720         boolean isSelected = false;
5721         boolean hasFocus = false;
5722 
5723         // Only indicate the selection and focused cell if not printing
5724         if (!isPaintingForPrint()) {
5725             isSelected = isCellSelected(row, column);
5726 
5727             boolean rowIsLead =
5728                 (selectionModel.getLeadSelectionIndex() == row);
5729             boolean colIsLead =
5730                 (columnModel.getSelectionModel().getLeadSelectionIndex() == column);
5731 
5732             hasFocus = (rowIsLead && colIsLead) && isFocusOwner();
5733         }
5734 
5735         return renderer.getTableCellRendererComponent(this, value,
5736                                                       isSelected, hasFocus,
5737                                                       row, column);
5738     }
5739 
5740     /**
5741      * Returns an appropriate editor for the cell specified by
5742      * <code>row</code> and <code>column</code>. If the
5743      * <code>TableColumn</code> for this column has a non-null editor,
5744      * returns that.  If not, finds the class of the data in this
5745      * column (using <code>getColumnClass</code>)
5746      * and returns the default editor for this type of data.
5747      * <p>
5748      * <b>Note:</b>
5749      * Throughout the table package, the internal implementations always
5750      * use this method to provide editors so that this default behavior
5751      * can be safely overridden by a subclass.
5752      *
5753      * @param row       the row of the cell to edit, where 0 is the first row
5754      * @param column    the column of the cell to edit,
5755      *                  where 0 is the first column
5756      * @return          the editor for this cell;
5757      *                  if <code>null</code> return the default editor for
5758      *                  this type of cell
5759      * @see DefaultCellEditor
5760      */
5761     public TableCellEditor getCellEditor(int row, int column) {
5762         TableColumn tableColumn = getColumnModel().getColumn(column);
5763         TableCellEditor editor = tableColumn.getCellEditor();
5764         if (editor == null) {
5765             editor = getDefaultEditor(getColumnClass(column));
5766         }
5767         return editor;
5768     }
5769 
5770 
5771     /**
5772      * Prepares the editor by querying the data model for the value and
5773      * selection state of the cell at <code>row</code>, <code>column</code>.
5774      * <p>
5775      * <b>Note:</b>
5776      * Throughout the table package, the internal implementations always
5777      * use this method to prepare editors so that this default behavior
5778      * can be safely overridden by a subclass.
5779      *
5780      * @param editor  the <code>TableCellEditor</code> to set up
5781      * @param row     the row of the cell to edit,
5782      *                where 0 is the first row
5783      * @param column  the column of the cell to edit,
5784      *                where 0 is the first column
5785      * @return the <code>Component</code> being edited
5786      */
5787     public Component prepareEditor(TableCellEditor editor, int row, int column) {
5788         Object value = getValueAt(row, column);
5789         boolean isSelected = isCellSelected(row, column);
5790         Component comp = editor.getTableCellEditorComponent(this, value, isSelected,
5791                                                   row, column);
5792         if (comp instanceof JComponent) {
5793             JComponent jComp = (JComponent)comp;
5794             if (jComp.getNextFocusableComponent() == null) {
5795                 jComp.setNextFocusableComponent(this);
5796             }
5797         }
5798         return comp;
5799     }
5800 
5801     /**
5802      * Discards the editor object and frees the real estate it used for
5803      * cell rendering.
5804      */
5805     public void removeEditor() {
5806         KeyboardFocusManager.getCurrentKeyboardFocusManager().
5807             removePropertyChangeListener("permanentFocusOwner", editorRemover);
5808         editorRemover = null;
5809 
5810         TableCellEditor editor = getCellEditor();
5811         if(editor != null) {
5812             editor.removeCellEditorListener(this);
5813             if (editorComp != null) {
5814                 Component focusOwner =
5815                         KeyboardFocusManager.getCurrentKeyboardFocusManager().getFocusOwner();
5816                 boolean isFocusOwnerInTheTable = focusOwner != null?
5817                         SwingUtilities.isDescendingFrom(focusOwner, this):false;
5818                 remove(editorComp);
5819                 if(isFocusOwnerInTheTable) {
5820                     requestFocusInWindow();
5821                 }
5822             }
5823 
5824             Rectangle cellRect = getCellRect(editingRow, editingColumn, false);
5825 
5826             setCellEditor(null);
5827             setEditingColumn(-1);
5828             setEditingRow(-1);
5829             editorComp = null;
5830 
5831             repaint(cellRect);
5832         }
5833     }
5834 
5835 //
5836 // Serialization
5837 //
5838 
5839     /**
5840      * See readObject() and writeObject() in JComponent for more
5841      * information about serialization in Swing.
5842      */
5843     private void writeObject(ObjectOutputStream s) throws IOException {
5844         s.defaultWriteObject();
5845         if (getUIClassID().equals(uiClassID)) {
5846             byte count = JComponent.getWriteObjCounter(this);
5847             JComponent.setWriteObjCounter(this, --count);
5848             if (count == 0 && ui != null) {
5849                 ui.installUI(this);
5850             }
5851         }
5852     }
5853 
5854     private void readObject(ObjectInputStream s)
5855         throws IOException, ClassNotFoundException
5856     {
5857         s.defaultReadObject();
5858         if ((ui != null) && (getUIClassID().equals(uiClassID))) {
5859             ui.installUI(this);
5860         }
5861         createDefaultRenderers();
5862         createDefaultEditors();
5863 
5864         // If ToolTipText != null, then the tooltip has already been
5865         // registered by JComponent.readObject() and we don't want
5866         // to re-register here
5867         if (getToolTipText() == null) {
5868             ToolTipManager.sharedInstance().registerComponent(this);
5869          }
5870     }
5871 
5872     /* Called from the JComponent's EnableSerializationFocusListener to
5873      * do any Swing-specific pre-serialization configuration.
5874      */
5875     void compWriteObjectNotify() {
5876         super.compWriteObjectNotify();
5877         // If ToolTipText != null, then the tooltip has already been
5878         // unregistered by JComponent.compWriteObjectNotify()
5879         if (getToolTipText() == null) {
5880             ToolTipManager.sharedInstance().unregisterComponent(this);
5881         }
5882     }
5883 
5884     /**
5885      * Returns a string representation of this table. This method
5886      * is intended to be used only for debugging purposes, and the
5887      * content and format of the returned string may vary between
5888      * implementations. The returned string may be empty but may not
5889      * be <code>null</code>.
5890      *
5891      * @return  a string representation of this table
5892      */
5893     protected String paramString() {
5894         String gridColorString = (gridColor != null ?
5895                                   gridColor.toString() : "");
5896         String showHorizontalLinesString = (showHorizontalLines ?
5897                                             "true" : "false");
5898         String showVerticalLinesString = (showVerticalLines ?
5899                                           "true" : "false");
5900         String autoResizeModeString;
5901         if (autoResizeMode == AUTO_RESIZE_OFF) {
5902             autoResizeModeString = "AUTO_RESIZE_OFF";
5903         } else if (autoResizeMode == AUTO_RESIZE_NEXT_COLUMN) {
5904             autoResizeModeString = "AUTO_RESIZE_NEXT_COLUMN";
5905         } else if (autoResizeMode == AUTO_RESIZE_SUBSEQUENT_COLUMNS) {
5906             autoResizeModeString = "AUTO_RESIZE_SUBSEQUENT_COLUMNS";
5907         } else if (autoResizeMode == AUTO_RESIZE_LAST_COLUMN) {
5908             autoResizeModeString = "AUTO_RESIZE_LAST_COLUMN";
5909         } else if (autoResizeMode == AUTO_RESIZE_ALL_COLUMNS)  {
5910             autoResizeModeString = "AUTO_RESIZE_ALL_COLUMNS";
5911         } else autoResizeModeString = "";
5912         String autoCreateColumnsFromModelString = (autoCreateColumnsFromModel ?
5913                                                    "true" : "false");
5914         String preferredViewportSizeString = (preferredViewportSize != null ?
5915                                               preferredViewportSize.toString()
5916                                               : "");
5917         String rowSelectionAllowedString = (rowSelectionAllowed ?
5918                                             "true" : "false");
5919         String cellSelectionEnabledString = (cellSelectionEnabled ?
5920                                             "true" : "false");
5921         String selectionForegroundString = (selectionForeground != null ?
5922                                             selectionForeground.toString() :
5923                                             "");
5924         String selectionBackgroundString = (selectionBackground != null ?
5925                                             selectionBackground.toString() :
5926                                             "");
5927 
5928         return super.paramString() +
5929         ",autoCreateColumnsFromModel=" + autoCreateColumnsFromModelString +
5930         ",autoResizeMode=" + autoResizeModeString +
5931         ",cellSelectionEnabled=" + cellSelectionEnabledString +
5932         ",editingColumn=" + editingColumn +
5933         ",editingRow=" + editingRow +
5934         ",gridColor=" + gridColorString +
5935         ",preferredViewportSize=" + preferredViewportSizeString +
5936         ",rowHeight=" + rowHeight +
5937         ",rowMargin=" + rowMargin +
5938         ",rowSelectionAllowed=" + rowSelectionAllowedString +
5939         ",selectionBackground=" + selectionBackgroundString +
5940         ",selectionForeground=" + selectionForegroundString +
5941         ",showHorizontalLines=" + showHorizontalLinesString +
5942         ",showVerticalLines=" + showVerticalLinesString;
5943     }
5944 
5945     // This class tracks changes in the keyboard focus state. It is used
5946     // when the JTable is editing to determine when to cancel the edit.
5947     // If focus switches to a component outside of the jtable, but in the
5948     // same window, this will cancel editing.
5949     class CellEditorRemover implements PropertyChangeListener {
5950         KeyboardFocusManager focusManager;
5951 
5952         public CellEditorRemover(KeyboardFocusManager fm) {
5953             this.focusManager = fm;
5954         }
5955 
5956         public void propertyChange(PropertyChangeEvent ev) {
5957             if (!isEditing() || getClientProperty("terminateEditOnFocusLost") != Boolean.TRUE) {
5958                 return;
5959             }
5960 
5961             Component c = focusManager.getPermanentFocusOwner();
5962             while (c != null) {
5963                 if (c == JTable.this) {
5964                     // focus remains inside the table
5965                     return;
5966                 } else if ((c instanceof Window) ||
5967                            (c instanceof Applet && c.getParent() == null)) {
5968                     if (c == SwingUtilities.getRoot(JTable.this)) {
5969                         if (!getCellEditor().stopCellEditing()) {
5970                             getCellEditor().cancelCellEditing();
5971                         }
5972                     }
5973                     break;
5974                 }
5975                 c = c.getParent();
5976             }
5977         }
5978     }
5979 
5980 /////////////////
5981 // Printing Support
5982 /////////////////
5983 
5984     /**
5985      * A convenience method that displays a printing dialog, and then prints
5986      * this <code>JTable</code> in mode <code>PrintMode.FIT_WIDTH</code>,
5987      * with no header or footer text. A modal progress dialog, with an abort
5988      * option, will be shown for the duration of printing.
5989      * <p>
5990      * Note: In headless mode, no dialogs are shown and printing
5991      * occurs on the default printer.
5992      *
5993      * @return true, unless printing is cancelled by the user
5994      * @throws SecurityException if this thread is not allowed to
5995      *                           initiate a print job request
5996      * @throws PrinterException if an error in the print system causes the job
5997      *                          to be aborted
5998      * @see #print(JTable.PrintMode, MessageFormat, MessageFormat,
5999      *             boolean, PrintRequestAttributeSet, boolean, PrintService)
6000      * @see #getPrintable
6001      *
6002      * @since 1.5
6003      */
6004     public boolean print() throws PrinterException {
6005 
6006         return print(PrintMode.FIT_WIDTH);
6007     }
6008 
6009     /**
6010      * A convenience method that displays a printing dialog, and then prints
6011      * this <code>JTable</code> in the given printing mode,
6012      * with no header or footer text. A modal progress dialog, with an abort
6013      * option, will be shown for the duration of printing.
6014      * <p>
6015      * Note: In headless mode, no dialogs are shown and printing
6016      * occurs on the default printer.
6017      *
6018      * @param  printMode        the printing mode that the printable should use
6019      * @return true, unless printing is cancelled by the user
6020      * @throws SecurityException if this thread is not allowed to
6021      *                           initiate a print job request
6022      * @throws PrinterException if an error in the print system causes the job
6023      *                          to be aborted
6024      * @see #print(JTable.PrintMode, MessageFormat, MessageFormat,
6025      *             boolean, PrintRequestAttributeSet, boolean, PrintService)
6026      * @see #getPrintable
6027      *
6028      * @since 1.5
6029      */
6030     public boolean print(PrintMode printMode) throws PrinterException {
6031 
6032         return print(printMode, null, null);
6033     }
6034 
6035     /**
6036      * A convenience method that displays a printing dialog, and then prints
6037      * this <code>JTable</code> in the given printing mode,
6038      * with the specified header and footer text. A modal progress dialog,
6039      * with an abort option, will be shown for the duration of printing.
6040      * <p>
6041      * Note: In headless mode, no dialogs are shown and printing
6042      * occurs on the default printer.
6043      *
6044      * @param  printMode        the printing mode that the printable should use
6045      * @param  headerFormat     a <code>MessageFormat</code> specifying the text
6046      *                          to be used in printing a header,
6047      *                          or null for none
6048      * @param  footerFormat     a <code>MessageFormat</code> specifying the text
6049      *                          to be used in printing a footer,
6050      *                          or null for none
6051      * @return true, unless printing is cancelled by the user
6052      * @throws SecurityException if this thread is not allowed to
6053      *                           initiate a print job request
6054      * @throws PrinterException if an error in the print system causes the job
6055      *                          to be aborted
6056      * @see #print(JTable.PrintMode, MessageFormat, MessageFormat,
6057      *             boolean, PrintRequestAttributeSet, boolean, PrintService)
6058      * @see #getPrintable
6059      *
6060      * @since 1.5
6061      */
6062     public boolean print(PrintMode printMode,
6063                          MessageFormat headerFormat,
6064                          MessageFormat footerFormat) throws PrinterException {
6065 
6066         boolean showDialogs = !GraphicsEnvironment.isHeadless();
6067         return print(printMode, headerFormat, footerFormat,
6068                      showDialogs, null, showDialogs);
6069     }
6070 
6071     /**
6072      * Prints this table, as specified by the fully featured
6073      * {@link #print(JTable.PrintMode, MessageFormat, MessageFormat,
6074      * boolean, PrintRequestAttributeSet, boolean, PrintService) print}
6075      * method, with the default printer specified as the print service.
6076      *
6077      * @param  printMode        the printing mode that the printable should use
6078      * @param  headerFormat     a <code>MessageFormat</code> specifying the text
6079      *                          to be used in printing a header,
6080      *                          or <code>null</code> for none
6081      * @param  footerFormat     a <code>MessageFormat</code> specifying the text
6082      *                          to be used in printing a footer,
6083      *                          or <code>null</code> for none
6084      * @param  showPrintDialog  whether or not to display a print dialog
6085      * @param  attr             a <code>PrintRequestAttributeSet</code>
6086      *                          specifying any printing attributes,
6087      *                          or <code>null</code> for none
6088      * @param  interactive      whether or not to print in an interactive mode
6089      * @return true, unless printing is cancelled by the user
6090      * @throws HeadlessException if the method is asked to show a printing
6091      *                           dialog or run interactively, and
6092      *                           <code>GraphicsEnvironment.isHeadless</code>
6093      *                           returns <code>true</code>
6094      * @throws SecurityException if this thread is not allowed to
6095      *                           initiate a print job request
6096      * @throws PrinterException if an error in the print system causes the job
6097      *                          to be aborted
6098      * @see #print(JTable.PrintMode, MessageFormat, MessageFormat,
6099      *             boolean, PrintRequestAttributeSet, boolean, PrintService)
6100      * @see #getPrintable
6101      *
6102      * @since 1.5
6103      */
6104     public boolean print(PrintMode printMode,
6105                          MessageFormat headerFormat,
6106                          MessageFormat footerFormat,
6107                          boolean showPrintDialog,
6108                          PrintRequestAttributeSet attr,
6109                          boolean interactive) throws PrinterException,
6110                                                      HeadlessException {
6111 
6112         return print(printMode,
6113                      headerFormat,
6114                      footerFormat,
6115                      showPrintDialog,
6116                      attr,
6117                      interactive,
6118                      null);
6119     }
6120 
6121     /**
6122      * Prints this <code>JTable</code>. Takes steps that the majority of
6123      * developers would take in order to print a <code>JTable</code>.
6124      * In short, it prepares the table, calls <code>getPrintable</code> to
6125      * fetch an appropriate <code>Printable</code>, and then sends it to the
6126      * printer.
6127      * <p>
6128      * A <code>boolean</code> parameter allows you to specify whether or not
6129      * a printing dialog is displayed to the user. When it is, the user may
6130      * use the dialog to change the destination printer or printing attributes,
6131      * or even to cancel the print. Another two parameters allow for a
6132      * <code>PrintService</code> and printing attributes to be specified.
6133      * These parameters can be used either to provide initial values for the
6134      * print dialog, or to specify values when the dialog is not shown.
6135      * <p>
6136      * A second <code>boolean</code> parameter allows you to specify whether
6137      * or not to perform printing in an interactive mode. If <code>true</code>,
6138      * a modal progress dialog, with an abort option, is displayed for the
6139      * duration of printing . This dialog also prevents any user action which
6140      * may affect the table. However, it can not prevent the table from being
6141      * modified by code (for example, another thread that posts updates using
6142      * <code>SwingUtilities.invokeLater</code>). It is therefore the
6143      * responsibility of the developer to ensure that no other code modifies
6144      * the table in any way during printing (invalid modifications include
6145      * changes in: size, renderers, or underlying data). Printing behavior is
6146      * undefined when the table is changed during printing.
6147      * <p>
6148      * If <code>false</code> is specified for this parameter, no dialog will
6149      * be displayed and printing will begin immediately on the event-dispatch
6150      * thread. This blocks any other events, including repaints, from being
6151      * processed until printing is complete. Although this effectively prevents
6152      * the table from being changed, it doesn't provide a good user experience.
6153      * For this reason, specifying <code>false</code> is only recommended when
6154      * printing from an application with no visible GUI.
6155      * <p>
6156      * Note: Attempting to show the printing dialog or run interactively, while
6157      * in headless mode, will result in a <code>HeadlessException</code>.
6158      * <p>
6159      * Before fetching the printable, this method will gracefully terminate
6160      * editing, if necessary, to prevent an editor from showing in the printed
6161      * result. Additionally, <code>JTable</code> will prepare its renderers
6162      * during printing such that selection and focus are not indicated.
6163      * As far as customizing further how the table looks in the printout,
6164      * developers can provide custom renderers or paint code that conditionalize
6165      * on the value of {@link javax.swing.JComponent#isPaintingForPrint()}.
6166      * <p>
6167      * See {@link #getPrintable} for more description on how the table is
6168      * printed.
6169      *
6170      * @param  printMode        the printing mode that the printable should use
6171      * @param  headerFormat     a <code>MessageFormat</code> specifying the text
6172      *                          to be used in printing a header,
6173      *                          or <code>null</code> for none
6174      * @param  footerFormat     a <code>MessageFormat</code> specifying the text
6175      *                          to be used in printing a footer,
6176      *                          or <code>null</code> for none
6177      * @param  showPrintDialog  whether or not to display a print dialog
6178      * @param  attr             a <code>PrintRequestAttributeSet</code>
6179      *                          specifying any printing attributes,
6180      *                          or <code>null</code> for none
6181      * @param  interactive      whether or not to print in an interactive mode
6182      * @param  service          the destination <code>PrintService</code>,
6183      *                          or <code>null</code> to use the default printer
6184      * @return true, unless printing is cancelled by the user
6185      * @throws HeadlessException if the method is asked to show a printing
6186      *                           dialog or run interactively, and
6187      *                           <code>GraphicsEnvironment.isHeadless</code>
6188      *                           returns <code>true</code>
6189      * @throws  SecurityException if a security manager exists and its
6190      *          {@link java.lang.SecurityManager#checkPrintJobAccess}
6191      *          method disallows this thread from creating a print job request
6192      * @throws PrinterException if an error in the print system causes the job
6193      *                          to be aborted
6194      * @see #getPrintable
6195      * @see java.awt.GraphicsEnvironment#isHeadless
6196      *
6197      * @since 1.6
6198      */
6199     public boolean print(PrintMode printMode,
6200                          MessageFormat headerFormat,
6201                          MessageFormat footerFormat,
6202                          boolean showPrintDialog,
6203                          PrintRequestAttributeSet attr,
6204                          boolean interactive,
6205                          PrintService service) throws PrinterException,
6206                                                       HeadlessException {
6207 
6208         // complain early if an invalid parameter is specified for headless mode
6209         boolean isHeadless = GraphicsEnvironment.isHeadless();
6210         if (isHeadless) {
6211             if (showPrintDialog) {
6212                 throw new HeadlessException("Can't show print dialog.");
6213             }
6214 
6215             if (interactive) {
6216                 throw new HeadlessException("Can't run interactively.");
6217             }
6218         }
6219 
6220         // Get a PrinterJob.
6221         // Do this before anything with side-effects since it may throw a
6222         // security exception - in which case we don't want to do anything else.
6223         final PrinterJob job = PrinterJob.getPrinterJob();
6224 
6225         if (isEditing()) {
6226             // try to stop cell editing, and failing that, cancel it
6227             if (!getCellEditor().stopCellEditing()) {
6228                 getCellEditor().cancelCellEditing();
6229             }
6230         }
6231 
6232         if (attr == null) {
6233             attr = new HashPrintRequestAttributeSet();
6234         }
6235 
6236         final PrintingStatus printingStatus;
6237 
6238          // fetch the Printable
6239         Printable printable =
6240              getPrintable(printMode, headerFormat, footerFormat);
6241 
6242         if (interactive) {
6243             // wrap the Printable so that we can print on another thread
6244             printable = new ThreadSafePrintable(printable);
6245             printingStatus = PrintingStatus.createPrintingStatus(this, job);
6246             printable = printingStatus.createNotificationPrintable(printable);
6247         } else {
6248             // to please compiler
6249             printingStatus = null;
6250         }
6251 
6252         // set the printable on the PrinterJob
6253         job.setPrintable(printable);
6254 
6255         // if specified, set the PrintService on the PrinterJob
6256         if (service != null) {
6257             job.setPrintService(service);
6258         }
6259 
6260         // if requested, show the print dialog
6261         if (showPrintDialog && !job.printDialog(attr)) {
6262             // the user cancelled the print dialog
6263             return false;
6264         }
6265 
6266         // if not interactive, just print on this thread (no dialog)
6267         if (!interactive) {
6268             // do the printing
6269             job.print(attr);
6270 
6271             // we're done
6272             return true;
6273         }
6274 
6275         // make sure this is clear since we'll check it after
6276         printError = null;
6277 
6278         // to synchronize on
6279         final Object lock = new Object();
6280 
6281         // copied so we can access from the inner class
6282         final PrintRequestAttributeSet copyAttr = attr;
6283 
6284         // this runnable will be used to do the printing
6285         // (and save any throwables) on another thread
6286         Runnable runnable = new Runnable() {
6287             public void run() {
6288                 try {
6289                     // do the printing
6290                     job.print(copyAttr);
6291                 } catch (Throwable t) {
6292                     // save any Throwable to be rethrown
6293                     synchronized(lock) {
6294                         printError = t;
6295                     }
6296                 } finally {
6297                     // we're finished - hide the dialog
6298                     printingStatus.dispose();
6299                 }
6300             }
6301         };
6302 
6303         // start printing on another thread
6304         Thread th = new Thread(runnable);
6305         th.start();
6306 
6307         printingStatus.showModal(true);
6308 
6309         // look for any error that the printing may have generated
6310         Throwable pe;
6311         synchronized(lock) {
6312             pe = printError;
6313             printError = null;
6314         }
6315 
6316         // check the type of error and handle it
6317         if (pe != null) {
6318             // a subclass of PrinterException meaning the job was aborted,
6319             // in this case, by the user
6320             if (pe instanceof PrinterAbortException) {
6321                 return false;
6322             } else if (pe instanceof PrinterException) {
6323                 throw (PrinterException)pe;
6324             } else if (pe instanceof RuntimeException) {
6325                 throw (RuntimeException)pe;
6326             } else if (pe instanceof Error) {
6327                 throw (Error)pe;
6328             }
6329 
6330             // can not happen
6331             throw new AssertionError(pe);
6332         }
6333 
6334         return true;
6335     }
6336 
6337     /**
6338      * Return a <code>Printable</code> for use in printing this JTable.
6339      * <p>
6340      * This method is meant for those wishing to customize the default
6341      * <code>Printable</code> implementation used by <code>JTable</code>'s
6342      * <code>print</code> methods. Developers wanting simply to print the table
6343      * should use one of those methods directly.
6344      * <p>
6345      * The <code>Printable</code> can be requested in one of two printing modes.
6346      * In both modes, it spreads table rows naturally in sequence across
6347      * multiple pages, fitting as many rows as possible per page.
6348      * <code>PrintMode.NORMAL</code> specifies that the table be
6349      * printed at its current size. In this mode, there may be a need to spread
6350      * columns across pages in a similar manner to that of the rows. When the
6351      * need arises, columns are distributed in an order consistent with the
6352      * table's <code>ComponentOrientation</code>.
6353      * <code>PrintMode.FIT_WIDTH</code> specifies that the output be
6354      * scaled smaller, if necessary, to fit the table's entire width
6355      * (and thereby all columns) on each page. Width and height are scaled
6356      * equally, maintaining the aspect ratio of the output.
6357      * <p>
6358      * The <code>Printable</code> heads the portion of table on each page
6359      * with the appropriate section from the table's <code>JTableHeader</code>,
6360      * if it has one.
6361      * <p>
6362      * Header and footer text can be added to the output by providing
6363      * <code>MessageFormat</code> arguments. The printing code requests
6364      * Strings from the formats, providing a single item which may be included
6365      * in the formatted string: an <code>Integer</code> representing the current
6366      * page number.
6367      * <p>
6368      * You are encouraged to read the documentation for
6369      * <code>MessageFormat</code> as some characters, such as single-quote,
6370      * are special and need to be escaped.
6371      * <p>
6372      * Here's an example of creating a <code>MessageFormat</code> that can be
6373      * used to print "Duke's Table: Page - " and the current page number:
6374      * <p>
6375      * <pre>
6376      *     // notice the escaping of the single quote
6377      *     // notice how the page number is included with "{0}"
6378      *     MessageFormat format = new MessageFormat("Duke''s Table: Page - {0}");
6379      * </pre>
6380      * <p>
6381      * The <code>Printable</code> constrains what it draws to the printable
6382      * area of each page that it prints. Under certain circumstances, it may
6383      * find it impossible to fit all of a page's content into that area. In
6384      * these cases the output may be clipped, but the implementation
6385      * makes an effort to do something reasonable. Here are a few situations
6386      * where this is known to occur, and how they may be handled by this
6387      * particular implementation:
6388      * <ul>
6389      *   <li>In any mode, when the header or footer text is too wide to fit
6390      *       completely in the printable area -- print as much of the text as
6391      *       possible starting from the beginning, as determined by the table's
6392      *       <code>ComponentOrientation</code>.
6393      *   <li>In any mode, when a row is too tall to fit in the
6394      *       printable area -- print the upper-most portion of the row
6395      *       and paint no lower border on the table.
6396      *   <li>In <code>PrintMode.NORMAL</code> when a column
6397      *       is too wide to fit in the printable area -- print the center
6398      *       portion of the column and leave the left and right borders
6399      *       off the table.
6400      * </ul>
6401      * <p>
6402      * It is entirely valid for this <code>Printable</code> to be wrapped
6403      * inside another in order to create complex reports and documents. You may
6404      * even request that different pages be rendered into different sized
6405      * printable areas. The implementation must be prepared to handle this
6406      * (possibly by doing its layout calculations on the fly). However,
6407      * providing different heights to each page will likely not work well
6408      * with <code>PrintMode.NORMAL</code> when it has to spread columns
6409      * across pages.
6410      * <p>
6411      * As far as customizing how the table looks in the printed result,
6412      * <code>JTable</code> itself will take care of hiding the selection
6413      * and focus during printing. For additional customizations, your
6414      * renderers or painting code can customize the look based on the value
6415      * of {@link javax.swing.JComponent#isPaintingForPrint()}
6416      * <p>
6417      * Also, <i>before</i> calling this method you may wish to <i>first</i>
6418      * modify the state of the table, such as to cancel cell editing or
6419      * have the user size the table appropriately. However, you must not
6420      * modify the state of the table <i>after</i> this <code>Printable</code>
6421      * has been fetched (invalid modifications include changes in size or
6422      * underlying data). The behavior of the returned <code>Printable</code>
6423      * is undefined once the table has been changed.
6424      *
6425      * @param  printMode     the printing mode that the printable should use
6426      * @param  headerFormat  a <code>MessageFormat</code> specifying the text to
6427      *                       be used in printing a header, or null for none
6428      * @param  footerFormat  a <code>MessageFormat</code> specifying the text to
6429      *                       be used in printing a footer, or null for none
6430      * @return a <code>Printable</code> for printing this JTable
6431      * @see #print(JTable.PrintMode, MessageFormat, MessageFormat,
6432      *             boolean, PrintRequestAttributeSet, boolean)
6433      * @see Printable
6434      * @see PrinterJob
6435      *
6436      * @since 1.5
6437      */
6438     public Printable getPrintable(PrintMode printMode,
6439                                   MessageFormat headerFormat,
6440                                   MessageFormat footerFormat) {
6441 
6442         return new TablePrintable(this, printMode, headerFormat, footerFormat);
6443     }
6444 
6445 
6446     /**
6447      * A <code>Printable</code> implementation that wraps another
6448      * <code>Printable</code>, making it safe for printing on another thread.
6449      */
6450     private class ThreadSafePrintable implements Printable {
6451 
6452         /** The delegate <code>Printable</code>. */
6453         private Printable printDelegate;
6454 
6455         /**
6456          * To communicate any return value when delegating.
6457          */
6458         private int retVal;
6459 
6460         /**
6461          * To communicate any <code>Throwable</code> when delegating.
6462          */
6463         private Throwable retThrowable;
6464 
6465         /**
6466          * Construct a <code>ThreadSafePrintable</code> around the given
6467          * delegate.
6468          *
6469          * @param printDelegate the <code>Printable</code> to delegate to
6470          */
6471         public ThreadSafePrintable(Printable printDelegate) {
6472             this.printDelegate = printDelegate;
6473         }
6474 
6475         /**
6476          * Prints the specified page into the given {@link Graphics}
6477          * context, in the specified format.
6478          * <p>
6479          * Regardless of what thread this method is called on, all calls into
6480          * the delegate will be done on the event-dispatch thread.
6481          *
6482          * @param   graphics    the context into which the page is drawn
6483          * @param   pageFormat  the size and orientation of the page being drawn
6484          * @param   pageIndex   the zero based index of the page to be drawn
6485          * @return  PAGE_EXISTS if the page is rendered successfully, or
6486          *          NO_SUCH_PAGE if a non-existent page index is specified
6487          * @throws  PrinterException if an error causes printing to be aborted
6488          */
6489         public int print(final Graphics graphics,
6490                          final PageFormat pageFormat,
6491                          final int pageIndex) throws PrinterException {
6492 
6493             // We'll use this Runnable
6494             Runnable runnable = new Runnable() {
6495                 public synchronized void run() {
6496                     try {
6497                         // call into the delegate and save the return value
6498                         retVal = printDelegate.print(graphics, pageFormat, pageIndex);
6499                     } catch (Throwable throwable) {
6500                         // save any Throwable to be rethrown
6501                         retThrowable = throwable;
6502                     } finally {
6503                         // notify the caller that we're done
6504                         notifyAll();
6505                     }
6506                 }
6507             };
6508 
6509             synchronized(runnable) {
6510                 // make sure these are initialized
6511                 retVal = -1;
6512                 retThrowable = null;
6513 
6514                 // call into the EDT
6515                 SwingUtilities.invokeLater(runnable);
6516 
6517                 // wait for the runnable to finish
6518                 while (retVal == -1 && retThrowable == null) {
6519                     try {
6520                         runnable.wait();
6521                     } catch (InterruptedException ie) {
6522                         // short process, safe to ignore interrupts
6523                     }
6524                 }
6525 
6526                 // if the delegate threw a throwable, rethrow it here
6527                 if (retThrowable != null) {
6528                     if (retThrowable instanceof PrinterException) {
6529                         throw (PrinterException)retThrowable;
6530                     } else if (retThrowable instanceof RuntimeException) {
6531                         throw (RuntimeException)retThrowable;
6532                     } else if (retThrowable instanceof Error) {
6533                         throw (Error)retThrowable;
6534                     }
6535 
6536                     // can not happen
6537                     throw new AssertionError(retThrowable);
6538                 }
6539 
6540                 return retVal;
6541             }
6542         }
6543     }
6544 
6545 
6546 /////////////////
6547 // Accessibility support
6548 ////////////////
6549 
6550     /**
6551      * Gets the AccessibleContext associated with this JTable.
6552      * For tables, the AccessibleContext takes the form of an
6553      * AccessibleJTable.
6554      * A new AccessibleJTable instance is created if necessary.
6555      *
6556      * @return an AccessibleJTable that serves as the
6557      *         AccessibleContext of this JTable
6558      */
6559     public AccessibleContext getAccessibleContext() {
6560         if (accessibleContext == null) {
6561             accessibleContext = new AccessibleJTable();
6562         }
6563         return accessibleContext;
6564     }
6565 
6566     //
6567     // *** should also implement AccessibleSelection?
6568     // *** and what's up with keyboard navigation/manipulation?
6569     //
6570     /**
6571      * This class implements accessibility support for the
6572      * <code>JTable</code> class.  It provides an implementation of the
6573      * Java Accessibility API appropriate to table user-interface elements.
6574      * <p>
6575      * <strong>Warning:</strong>
6576      * Serialized objects of this class will not be compatible with
6577      * future Swing releases. The current serialization support is
6578      * appropriate for short term storage or RMI between applications running
6579      * the same version of Swing.  As of 1.4, support for long term storage
6580      * of all JavaBeans<sup><font size="-2">TM</font></sup>
6581      * has been added to the <code>java.beans</code> package.
6582      * Please see {@link java.beans.XMLEncoder}.
6583      */
6584     protected class AccessibleJTable extends AccessibleJComponent
6585     implements AccessibleSelection, ListSelectionListener, TableModelListener,
6586     TableColumnModelListener, CellEditorListener, PropertyChangeListener,
6587     AccessibleExtendedTable {
6588 
6589         int lastSelectedRow;
6590         int lastSelectedCol;
6591 
6592         /**
6593          * AccessibleJTable constructor
6594          *
6595          * @since 1.5
6596          */
6597         protected AccessibleJTable() {
6598             super();
6599             JTable.this.addPropertyChangeListener(this);
6600             JTable.this.getSelectionModel().addListSelectionListener(this);
6601             TableColumnModel tcm = JTable.this.getColumnModel();
6602             tcm.addColumnModelListener(this);
6603             tcm.getSelectionModel().addListSelectionListener(this);
6604             JTable.this.getModel().addTableModelListener(this);
6605             lastSelectedRow = JTable.this.getSelectedRow();
6606             lastSelectedCol = JTable.this.getSelectedColumn();
6607         }
6608 
6609     // Listeners to track model, etc. changes to as to re-place the other
6610     // listeners
6611 
6612         /**
6613          * Track changes to selection model, column model, etc. so as to
6614          * be able to re-place listeners on those in order to pass on
6615          * information to the Accessibility PropertyChange mechanism
6616          */
6617         public void propertyChange(PropertyChangeEvent e) {
6618             String name = e.getPropertyName();
6619             Object oldValue = e.getOldValue();
6620             Object newValue = e.getNewValue();
6621 
6622                 // re-set tableModel listeners
6623             if (name.compareTo("model") == 0) {
6624 
6625                 if (oldValue != null && oldValue instanceof TableModel) {
6626                     ((TableModel) oldValue).removeTableModelListener(this);
6627                 }
6628                 if (newValue != null && newValue instanceof TableModel) {
6629                     ((TableModel) newValue).addTableModelListener(this);
6630                 }
6631 
6632                 // re-set selectionModel listeners
6633             } else if (name.compareTo("selectionModel") == 0) {
6634 
6635                 Object source = e.getSource();
6636                 if (source == JTable.this) {    // row selection model
6637 
6638                     if (oldValue != null &&
6639                         oldValue instanceof ListSelectionModel) {
6640                         ((ListSelectionModel) oldValue).removeListSelectionListener(this);
6641                     }
6642                     if (newValue != null &&
6643                         newValue instanceof ListSelectionModel) {
6644                         ((ListSelectionModel) newValue).addListSelectionListener(this);
6645                     }
6646 
6647                 } else if (source == JTable.this.getColumnModel()) {
6648 
6649                     if (oldValue != null &&
6650                         oldValue instanceof ListSelectionModel) {
6651                         ((ListSelectionModel) oldValue).removeListSelectionListener(this);
6652                     }
6653                     if (newValue != null &&
6654                         newValue instanceof ListSelectionModel) {
6655                         ((ListSelectionModel) newValue).addListSelectionListener(this);
6656                     }
6657 
6658                 } else {
6659                   //        System.out.println("!!! Bug in source of selectionModel propertyChangeEvent");
6660                 }
6661 
6662                 // re-set columnModel listeners
6663                 // and column's selection property listener as well
6664             } else if (name.compareTo("columnModel") == 0) {
6665 
6666                 if (oldValue != null && oldValue instanceof TableColumnModel) {
6667                     TableColumnModel tcm = (TableColumnModel) oldValue;
6668                     tcm.removeColumnModelListener(this);
6669                     tcm.getSelectionModel().removeListSelectionListener(this);
6670                 }
6671                 if (newValue != null && newValue instanceof TableColumnModel) {
6672                     TableColumnModel tcm = (TableColumnModel) newValue;
6673                     tcm.addColumnModelListener(this);
6674                     tcm.getSelectionModel().addListSelectionListener(this);
6675                 }
6676 
6677                 // re-se cellEditor listeners
6678             } else if (name.compareTo("tableCellEditor") == 0) {
6679 
6680                 if (oldValue != null && oldValue instanceof TableCellEditor) {
6681                     ((TableCellEditor) oldValue).removeCellEditorListener(this);
6682                 }
6683                 if (newValue != null && newValue instanceof TableCellEditor) {
6684                     ((TableCellEditor) newValue).addCellEditorListener(this);
6685                 }
6686             }
6687         }
6688 
6689 
6690     // Listeners to echo changes to the AccessiblePropertyChange mechanism
6691 
6692         /*
6693          * Describes a change in the accessible table model.
6694          */
6695         protected class AccessibleJTableModelChange
6696             implements AccessibleTableModelChange {
6697 
6698             protected int type;
6699             protected int firstRow;
6700             protected int lastRow;
6701             protected int firstColumn;
6702             protected int lastColumn;
6703 
6704             protected AccessibleJTableModelChange(int type, int firstRow,
6705                                                   int lastRow, int firstColumn,
6706                                                   int lastColumn) {
6707                 this.type = type;
6708                 this.firstRow = firstRow;
6709                 this.lastRow = lastRow;
6710                 this.firstColumn = firstColumn;
6711                 this.lastColumn = lastColumn;
6712             }
6713 
6714             public int getType() {
6715                 return type;
6716             }
6717 
6718             public int getFirstRow() {
6719                 return firstRow;
6720             }
6721 
6722             public int getLastRow() {
6723                 return lastRow;
6724             }
6725 
6726             public int getFirstColumn() {
6727                 return firstColumn;
6728             }
6729 
6730             public int getLastColumn() {
6731                 return lastColumn;
6732             }
6733         }
6734 
6735         /**
6736          * Track changes to the table contents
6737          */
6738         public void tableChanged(TableModelEvent e) {
6739            firePropertyChange(AccessibleContext.ACCESSIBLE_VISIBLE_DATA_PROPERTY,
6740                               null, null);
6741            if (e != null) {
6742                int firstColumn = e.getColumn();
6743                int lastColumn = e.getColumn();
6744                if (firstColumn == TableModelEvent.ALL_COLUMNS) {
6745                    firstColumn = 0;
6746                    lastColumn = getColumnCount() - 1;
6747                }
6748 
6749                // Fire a property change event indicating the table model
6750                // has changed.
6751                AccessibleJTableModelChange change =
6752                    new AccessibleJTableModelChange(e.getType(),
6753                                                    e.getFirstRow(),
6754                                                    e.getLastRow(),
6755                                                    firstColumn,
6756                                                    lastColumn);
6757                firePropertyChange(AccessibleContext.ACCESSIBLE_TABLE_MODEL_CHANGED,
6758                                   null, change);
6759             }
6760         }
6761 
6762         /**
6763          * Track changes to the table contents (row insertions)
6764          */
6765         public void tableRowsInserted(TableModelEvent e) {
6766            firePropertyChange(AccessibleContext.ACCESSIBLE_VISIBLE_DATA_PROPERTY,
6767                               null, null);
6768 
6769            // Fire a property change event indicating the table model
6770            // has changed.
6771            int firstColumn = e.getColumn();
6772            int lastColumn = e.getColumn();
6773            if (firstColumn == TableModelEvent.ALL_COLUMNS) {
6774                firstColumn = 0;
6775                lastColumn = getColumnCount() - 1;
6776            }
6777            AccessibleJTableModelChange change =
6778                new AccessibleJTableModelChange(e.getType(),
6779                                                e.getFirstRow(),
6780                                                e.getLastRow(),
6781                                                firstColumn,
6782                                                lastColumn);
6783            firePropertyChange(AccessibleContext.ACCESSIBLE_TABLE_MODEL_CHANGED,
6784                               null, change);
6785         }
6786 
6787         /**
6788          * Track changes to the table contents (row deletions)
6789          */
6790         public void tableRowsDeleted(TableModelEvent e) {
6791            firePropertyChange(AccessibleContext.ACCESSIBLE_VISIBLE_DATA_PROPERTY,
6792                               null, null);
6793 
6794            // Fire a property change event indicating the table model
6795            // has changed.
6796            int firstColumn = e.getColumn();
6797            int lastColumn = e.getColumn();
6798            if (firstColumn == TableModelEvent.ALL_COLUMNS) {
6799                firstColumn = 0;
6800                lastColumn = getColumnCount() - 1;
6801            }
6802            AccessibleJTableModelChange change =
6803                new AccessibleJTableModelChange(e.getType(),
6804                                                e.getFirstRow(),
6805                                                e.getLastRow(),
6806                                                firstColumn,
6807                                                lastColumn);
6808            firePropertyChange(AccessibleContext.ACCESSIBLE_TABLE_MODEL_CHANGED,
6809                               null, change);
6810         }
6811 
6812         /**
6813          * Track changes to the table contents (column insertions)
6814          */
6815         public void columnAdded(TableColumnModelEvent e) {
6816            firePropertyChange(AccessibleContext.ACCESSIBLE_VISIBLE_DATA_PROPERTY,
6817                               null, null);
6818 
6819            // Fire a property change event indicating the table model
6820            // has changed.
6821            int type = AccessibleTableModelChange.INSERT;
6822            AccessibleJTableModelChange change =
6823                new AccessibleJTableModelChange(type,
6824                                                0,
6825                                                0,
6826                                                e.getFromIndex(),
6827                                                e.getToIndex());
6828            firePropertyChange(AccessibleContext.ACCESSIBLE_TABLE_MODEL_CHANGED,
6829                               null, change);
6830         }
6831 
6832         /**
6833          * Track changes to the table contents (column deletions)
6834          */
6835         public void columnRemoved(TableColumnModelEvent e) {
6836            firePropertyChange(AccessibleContext.ACCESSIBLE_VISIBLE_DATA_PROPERTY,
6837                               null, null);
6838            // Fire a property change event indicating the table model
6839            // has changed.
6840            int type = AccessibleTableModelChange.DELETE;
6841            AccessibleJTableModelChange change =
6842                new AccessibleJTableModelChange(type,
6843                                                0,
6844                                                0,
6845                                                e.getFromIndex(),
6846                                                e.getToIndex());
6847            firePropertyChange(AccessibleContext.ACCESSIBLE_TABLE_MODEL_CHANGED,
6848                               null, change);
6849         }
6850 
6851         /**
6852          * Track changes of a column repositioning.
6853          *
6854          * @see TableColumnModelListener
6855          */
6856         public void columnMoved(TableColumnModelEvent e) {
6857            firePropertyChange(AccessibleContext.ACCESSIBLE_VISIBLE_DATA_PROPERTY,
6858                               null, null);
6859 
6860            // Fire property change events indicating the table model
6861            // has changed.
6862            int type = AccessibleTableModelChange.DELETE;
6863            AccessibleJTableModelChange change =
6864                new AccessibleJTableModelChange(type,
6865                                                0,
6866                                                0,
6867                                                e.getFromIndex(),
6868                                                e.getFromIndex());
6869            firePropertyChange(AccessibleContext.ACCESSIBLE_TABLE_MODEL_CHANGED,
6870                               null, change);
6871 
6872            int type2 = AccessibleTableModelChange.INSERT;
6873            AccessibleJTableModelChange change2 =
6874                new AccessibleJTableModelChange(type2,
6875                                                0,
6876                                                0,
6877                                                e.getToIndex(),
6878                                                e.getToIndex());
6879            firePropertyChange(AccessibleContext.ACCESSIBLE_TABLE_MODEL_CHANGED,
6880                               null, change2);
6881         }
6882 
6883         /**
6884          * Track changes of a column moving due to margin changes.
6885          *
6886          * @see TableColumnModelListener
6887          */
6888         public void columnMarginChanged(ChangeEvent e) {
6889            firePropertyChange(AccessibleContext.ACCESSIBLE_VISIBLE_DATA_PROPERTY,
6890                               null, null);
6891         }
6892 
6893         /**
6894          * Track that the selection model of the TableColumnModel changed.
6895          *
6896          * @see TableColumnModelListener
6897          */
6898         public void columnSelectionChanged(ListSelectionEvent e) {
6899             // we should now re-place our TableColumn listener
6900         }
6901 
6902         /**
6903          * Track changes to a cell's contents.
6904          *
6905          * Invoked when editing is finished. The changes are saved, the
6906          * editor object is discarded, and the cell is rendered once again.
6907          *
6908          * @see CellEditorListener
6909          */
6910         public void editingStopped(ChangeEvent e) {
6911            // it'd be great if we could figure out which cell, and pass that
6912            // somehow as a parameter
6913            firePropertyChange(AccessibleContext.ACCESSIBLE_VISIBLE_DATA_PROPERTY,
6914                               null, null);
6915         }
6916 
6917         /**
6918          * Invoked when editing is canceled. The editor object is discarded
6919          * and the cell is rendered once again.
6920          *
6921          * @see CellEditorListener
6922          */
6923         public void editingCanceled(ChangeEvent e) {
6924             // nothing to report, 'cause nothing changed
6925         }
6926 
6927         /**
6928          * Track changes to table cell selections
6929          */
6930         public void valueChanged(ListSelectionEvent e) {
6931             firePropertyChange(AccessibleContext.ACCESSIBLE_SELECTION_PROPERTY,
6932                                Boolean.valueOf(false), Boolean.valueOf(true));
6933 
6934             int selectedRow = JTable.this.getSelectedRow();
6935             int selectedCol = JTable.this.getSelectedColumn();
6936             if (selectedRow != lastSelectedRow ||
6937                 selectedCol != lastSelectedCol) {
6938                 Accessible oldA = getAccessibleAt(lastSelectedRow,
6939                                                   lastSelectedCol);
6940                 Accessible newA = getAccessibleAt(selectedRow, selectedCol);
6941                 firePropertyChange(AccessibleContext.ACCESSIBLE_ACTIVE_DESCENDANT_PROPERTY,
6942                                    oldA, newA);
6943                  lastSelectedRow = selectedRow;
6944                  lastSelectedCol = selectedCol;
6945              }
6946         }
6947 
6948 
6949 
6950 
6951     // AccessibleContext support
6952 
6953         /**
6954          * Get the AccessibleSelection associated with this object.  In the
6955          * implementation of the Java Accessibility API for this class,
6956          * return this object, which is responsible for implementing the
6957          * AccessibleSelection interface on behalf of itself.
6958          *
6959          * @return this object
6960          */
6961         public AccessibleSelection getAccessibleSelection() {
6962             return this;
6963         }
6964 
6965         /**
6966          * Gets the role of this object.
6967          *
6968          * @return an instance of AccessibleRole describing the role of the
6969          * object
6970          * @see AccessibleRole
6971          */
6972         public AccessibleRole getAccessibleRole() {
6973             return AccessibleRole.TABLE;
6974         }
6975 
6976         /**
6977          * Returns the <code>Accessible</code> child, if one exists,
6978          * contained at the local coordinate <code>Point</code>.
6979          *
6980          * @param p the point defining the top-left corner of the
6981          *    <code>Accessible</code>, given in the coordinate space
6982          *    of the object's parent
6983          * @return the <code>Accessible</code>, if it exists,
6984          *    at the specified location; else <code>null</code>
6985          */
6986         public Accessible getAccessibleAt(Point p) {
6987             int column = columnAtPoint(p);
6988             int row = rowAtPoint(p);
6989 
6990             if ((column != -1) && (row != -1)) {
6991                 TableColumn aColumn = getColumnModel().getColumn(column);
6992                 TableCellRenderer renderer = aColumn.getCellRenderer();
6993                 if (renderer == null) {
6994                     Class<?> columnClass = getColumnClass(column);
6995                     renderer = getDefaultRenderer(columnClass);
6996                 }
6997                 Component component = renderer.getTableCellRendererComponent(
6998                                   JTable.this, null, false, false,
6999                                   row, column);
7000                 return new AccessibleJTableCell(JTable.this, row, column,
7001                       getAccessibleIndexAt(row, column));
7002             }
7003             return null;
7004         }
7005 
7006         /**
7007          * Returns the number of accessible children in the object.  If all
7008          * of the children of this object implement <code>Accessible</code>,
7009          * then this method should return the number of children of this object.
7010          *
7011          * @return the number of accessible children in the object
7012          */
7013         public int getAccessibleChildrenCount() {
7014             return (JTable.this.getColumnCount() * JTable.this.getRowCount());
7015         }
7016 
7017         /**
7018          * Returns the nth <code>Accessible</code> child of the object.
7019          *
7020          * @param i zero-based index of child
7021          * @return the nth Accessible child of the object
7022          */
7023         public Accessible getAccessibleChild(int i) {
7024             if (i < 0 || i >= getAccessibleChildrenCount()) {
7025                 return null;
7026             } else {
7027                 // children increase across, and then down, for tables
7028                 // (arbitrary decision)
7029                 int column = getAccessibleColumnAtIndex(i);
7030                 int row = getAccessibleRowAtIndex(i);
7031 
7032                 TableColumn aColumn = getColumnModel().getColumn(column);
7033                 TableCellRenderer renderer = aColumn.getCellRenderer();
7034                 if (renderer == null) {
7035                     Class<?> columnClass = getColumnClass(column);
7036                     renderer = getDefaultRenderer(columnClass);
7037                 }
7038                 Component component = renderer.getTableCellRendererComponent(
7039                                   JTable.this, null, false, false,
7040                                   row, column);
7041                 return new AccessibleJTableCell(JTable.this, row, column,
7042                       getAccessibleIndexAt(row, column));
7043             }
7044         }
7045 
7046     // AccessibleSelection support
7047 
7048         /**
7049          * Returns the number of <code>Accessible</code> children
7050          * currently selected.
7051          * If no children are selected, the return value will be 0.
7052          *
7053          * @return the number of items currently selected
7054          */
7055         public int getAccessibleSelectionCount() {
7056             int rowsSel = JTable.this.getSelectedRowCount();
7057             int colsSel = JTable.this.getSelectedColumnCount();
7058 
7059             if (JTable.this.cellSelectionEnabled) { // a contiguous block
7060                 return rowsSel * colsSel;
7061 
7062             } else {
7063                 // a column swath and a row swath, with a shared block
7064                 if (JTable.this.getRowSelectionAllowed() &&
7065                     JTable.this.getColumnSelectionAllowed()) {
7066                     return rowsSel * JTable.this.getColumnCount() +
7067                            colsSel * JTable.this.getRowCount() -
7068                            rowsSel * colsSel;
7069 
7070                 // just one or more rows in selection
7071                 } else if (JTable.this.getRowSelectionAllowed()) {
7072                     return rowsSel * JTable.this.getColumnCount();
7073 
7074                 // just one or more rows in selection
7075                 } else if (JTable.this.getColumnSelectionAllowed()) {
7076                     return colsSel * JTable.this.getRowCount();
7077 
7078                 } else {
7079                     return 0;    // JTable doesn't allow selections
7080                 }
7081             }
7082         }
7083 
7084         /**
7085          * Returns an <code>Accessible</code> representing the
7086          * specified selected child in the object.  If there
7087          * isn't a selection, or there are fewer children selected
7088          * than the integer passed in, the return
7089          * value will be <code>null</code>.
7090          * <p>Note that the index represents the i-th selected child, which
7091          * is different from the i-th child.
7092          *
7093          * @param i the zero-based index of selected children
7094          * @return the i-th selected child
7095          * @see #getAccessibleSelectionCount
7096          */
7097         public Accessible getAccessibleSelection(int i) {
7098             if (i < 0 || i > getAccessibleSelectionCount()) {
7099                 return null;
7100             }
7101 
7102             int rowsSel = JTable.this.getSelectedRowCount();
7103             int colsSel = JTable.this.getSelectedColumnCount();
7104             int rowIndicies[] = getSelectedRows();
7105             int colIndicies[] = getSelectedColumns();
7106             int ttlCols = JTable.this.getColumnCount();
7107             int ttlRows = JTable.this.getRowCount();
7108             int r;
7109             int c;
7110 
7111             if (JTable.this.cellSelectionEnabled) { // a contiguous block
7112                 r = rowIndicies[i / colsSel];
7113                 c = colIndicies[i % colsSel];
7114                 return getAccessibleChild((r * ttlCols) + c);
7115             } else {
7116 
7117                 // a column swath and a row swath, with a shared block
7118                 if (JTable.this.getRowSelectionAllowed() &&
7119                     JTable.this.getColumnSelectionAllowed()) {
7120 
7121                     // Situation:
7122                     //   We have a table, like the 6x3 table below,
7123                     //   wherein three colums and one row selected
7124                     //   (selected cells marked with "*", unselected "0"):
7125                     //
7126                     //            0 * 0 * * 0
7127                     //            * * * * * *
7128                     //            0 * 0 * * 0
7129                     //
7130 
7131                     // State machine below walks through the array of
7132                     // selected rows in two states: in a selected row,
7133                     // and not in one; continuing until we are in a row
7134                     // in which the ith selection exists.  Then we return
7135                     // the appropriate cell.  In the state machine, we
7136                     // always do rows above the "current" selected row first,
7137                     // then the cells in the selected row.  If we're done
7138                     // with the state machine before finding the requested
7139                     // selected child, we handle the rows below the last
7140                     // selected row at the end.
7141                     //
7142                     int curIndex = i;
7143                     final int IN_ROW = 0;
7144                     final int NOT_IN_ROW = 1;
7145                     int state = (rowIndicies[0] == 0 ? IN_ROW : NOT_IN_ROW);
7146                     int j = 0;
7147                     int prevRow = -1;
7148                     while (j < rowIndicies.length) {
7149                         switch (state) {
7150 
7151                         case IN_ROW:   // on individual row full of selections
7152                             if (curIndex < ttlCols) { // it's here!
7153                                 c = curIndex % ttlCols;
7154                                 r = rowIndicies[j];
7155                                 return getAccessibleChild((r * ttlCols) + c);
7156                             } else {                               // not here
7157                                 curIndex -= ttlCols;
7158                             }
7159                             // is the next row in table selected or not?
7160                             if (j + 1 == rowIndicies.length ||
7161                                 rowIndicies[j] != rowIndicies[j+1] - 1) {
7162                                 state = NOT_IN_ROW;
7163                                 prevRow = rowIndicies[j];
7164                             }
7165                             j++;  // we didn't return earlier, so go to next row
7166                             break;
7167 
7168                         case NOT_IN_ROW:  // sparse bunch of rows of selections
7169                             if (curIndex <
7170                                 (colsSel * (rowIndicies[j] -
7171                                 (prevRow == -1 ? 0 : (prevRow + 1))))) {
7172 
7173                                 // it's here!
7174                                 c = colIndicies[curIndex % colsSel];
7175                                 r = (j > 0 ? rowIndicies[j-1] + 1 : 0)
7176                                     + curIndex / colsSel;
7177                                 return getAccessibleChild((r * ttlCols) + c);
7178                             } else {                               // not here
7179                                 curIndex -= colsSel * (rowIndicies[j] -
7180                                 (prevRow == -1 ? 0 : (prevRow + 1)));
7181                             }
7182                             state = IN_ROW;
7183                             break;
7184                         }
7185                     }
7186                     // we got here, so we didn't find it yet; find it in
7187                     // the last sparse bunch of rows
7188                     if (curIndex <
7189                         (colsSel * (ttlRows -
7190                         (prevRow == -1 ? 0 : (prevRow + 1))))) { // it's here!
7191                         c = colIndicies[curIndex % colsSel];
7192                         r = rowIndicies[j-1] + curIndex / colsSel + 1;
7193                         return getAccessibleChild((r * ttlCols) + c);
7194                     } else {                               // not here
7195                         // we shouldn't get to this spot in the code!
7196 //                      System.out.println("Bug in AccessibleJTable.getAccessibleSelection()");
7197                     }
7198 
7199                 // one or more rows selected
7200                 } else if (JTable.this.getRowSelectionAllowed()) {
7201                     c = i % ttlCols;
7202                     r = rowIndicies[i / ttlCols];
7203                     return getAccessibleChild((r * ttlCols) + c);
7204 
7205                 // one or more columns selected
7206                 } else if (JTable.this.getColumnSelectionAllowed()) {
7207                     c = colIndicies[i % colsSel];
7208                     r = i / colsSel;
7209                     return getAccessibleChild((r * ttlCols) + c);
7210                 }
7211             }
7212             return null;
7213         }
7214 
7215         /**
7216          * Determines if the current child of this object is selected.
7217          *
7218          * @param i the zero-based index of the child in this
7219          *    <code>Accessible</code> object
7220          * @return true if the current child of this object is selected
7221          * @see AccessibleContext#getAccessibleChild
7222          */
7223         public boolean isAccessibleChildSelected(int i) {
7224             int column = getAccessibleColumnAtIndex(i);
7225             int row = getAccessibleRowAtIndex(i);
7226             return JTable.this.isCellSelected(row, column);
7227         }
7228 
7229         /**
7230          * Adds the specified <code>Accessible</code> child of the
7231          * object to the object's selection.  If the object supports
7232          * multiple selections, the specified child is added to
7233          * any existing selection, otherwise
7234          * it replaces any existing selection in the object.  If the
7235          * specified child is already selected, this method has no effect.
7236          * <p>
7237          * This method only works on <code>JTable</code>s which have
7238          * individual cell selection enabled.
7239          *
7240          * @param i the zero-based index of the child
7241          * @see AccessibleContext#getAccessibleChild
7242          */
7243         public void addAccessibleSelection(int i) {
7244             // TIGER - 4495286
7245             int column = getAccessibleColumnAtIndex(i);
7246             int row = getAccessibleRowAtIndex(i);
7247             JTable.this.changeSelection(row, column, true, false);
7248         }
7249 
7250         /**
7251          * Removes the specified child of the object from the object's
7252          * selection.  If the specified item isn't currently selected, this
7253          * method has no effect.
7254          * <p>
7255          * This method only works on <code>JTables</code> which have
7256          * individual cell selection enabled.
7257          *
7258          * @param i the zero-based index of the child
7259          * @see AccessibleContext#getAccessibleChild
7260          */
7261         public void removeAccessibleSelection(int i) {
7262             if (JTable.this.cellSelectionEnabled) {
7263                 int column = getAccessibleColumnAtIndex(i);
7264                 int row = getAccessibleRowAtIndex(i);
7265                 JTable.this.removeRowSelectionInterval(row, row);
7266                 JTable.this.removeColumnSelectionInterval(column, column);
7267             }
7268         }
7269 
7270         /**
7271          * Clears the selection in the object, so that no children in the
7272          * object are selected.
7273          */
7274         public void clearAccessibleSelection() {
7275             JTable.this.clearSelection();
7276         }
7277 
7278         /**
7279          * Causes every child of the object to be selected, but only
7280          * if the <code>JTable</code> supports multiple selections,
7281          * and if individual cell selection is enabled.
7282          */
7283         public void selectAllAccessibleSelection() {
7284             if (JTable.this.cellSelectionEnabled) {
7285                 JTable.this.selectAll();
7286             }
7287         }
7288 
7289         // begin AccessibleExtendedTable implementation -------------
7290 
7291         /**
7292          * Returns the row number of an index in the table.
7293          *
7294          * @param index the zero-based index in the table
7295          * @return the zero-based row of the table if one exists;
7296          * otherwise -1.
7297          * @since 1.4
7298          */
7299         public int getAccessibleRow(int index) {
7300             return getAccessibleRowAtIndex(index);
7301         }
7302 
7303         /**
7304          * Returns the column number of an index in the table.
7305          *
7306          * @param index the zero-based index in the table
7307          * @return the zero-based column of the table if one exists;
7308          * otherwise -1.
7309          * @since 1.4
7310          */
7311         public int getAccessibleColumn(int index) {
7312             return getAccessibleColumnAtIndex(index);
7313         }
7314 
7315         /**
7316          * Returns the index at a row and column in the table.
7317          *
7318          * @param r zero-based row of the table
7319          * @param c zero-based column of the table
7320          * @return the zero-based index in the table if one exists;
7321          * otherwise -1.
7322          * @since 1.4
7323          */
7324         public int getAccessibleIndex(int r, int c) {
7325             return getAccessibleIndexAt(r, c);
7326         }
7327 
7328         // end of AccessibleExtendedTable implementation ------------
7329 
7330         // start of AccessibleTable implementation ------------------
7331 
7332         private Accessible caption;
7333         private Accessible summary;
7334         private Accessible [] rowDescription;
7335         private Accessible [] columnDescription;
7336 
7337         /**
7338          * Gets the <code>AccessibleTable</code> associated with this
7339          * object.  In the implementation of the Java Accessibility
7340          * API for this class, return this object, which is responsible
7341          * for implementing the <code>AccessibleTables</code> interface
7342          * on behalf of itself.
7343          *
7344          * @return this object
7345          * @since 1.3
7346          */
7347         public AccessibleTable getAccessibleTable() {
7348             return this;
7349         }
7350 
7351         /**
7352          * Returns the caption for the table.
7353          *
7354          * @return the caption for the table
7355          * @since 1.3
7356          */
7357         public Accessible getAccessibleCaption() {
7358             return this.caption;
7359         }
7360 
7361         /**
7362          * Sets the caption for the table.
7363          *
7364          * @param a the caption for the table
7365          * @since 1.3
7366          */
7367         public void setAccessibleCaption(Accessible a) {
7368             Accessible oldCaption = caption;
7369             this.caption = a;
7370             firePropertyChange(AccessibleContext.ACCESSIBLE_TABLE_CAPTION_CHANGED,
7371                                oldCaption, this.caption);
7372         }
7373 
7374         /**
7375          * Returns the summary description of the table.
7376          *
7377          * @return the summary description of the table
7378          * @since 1.3
7379          */
7380         public Accessible getAccessibleSummary() {
7381             return this.summary;
7382         }
7383 
7384         /**
7385          * Sets the summary description of the table.
7386          *
7387          * @param a the summary description of the table
7388          * @since 1.3
7389          */
7390         public void setAccessibleSummary(Accessible a) {
7391             Accessible oldSummary = summary;
7392             this.summary = a;
7393             firePropertyChange(AccessibleContext.ACCESSIBLE_TABLE_SUMMARY_CHANGED,
7394                                oldSummary, this.summary);
7395         }
7396 
7397         /*
7398          * Returns the total number of rows in this table.
7399          *
7400          * @return the total number of rows in this table
7401          */
7402         public int getAccessibleRowCount() {
7403             return JTable.this.getRowCount();
7404         }
7405 
7406         /*
7407          * Returns the total number of columns in the table.
7408          *
7409          * @return the total number of columns in the table
7410          */
7411         public int getAccessibleColumnCount() {
7412             return JTable.this.getColumnCount();
7413         }
7414 
7415         /*
7416          * Returns the <code>Accessible</code> at a specified row
7417          * and column in the table.
7418          *
7419          * @param r zero-based row of the table
7420          * @param c zero-based column of the table
7421          * @return the <code>Accessible</code> at the specified row and column
7422          * in the table
7423          */
7424         public Accessible getAccessibleAt(int r, int c) {
7425             return getAccessibleChild((r * getAccessibleColumnCount()) + c);
7426         }
7427 
7428         /**
7429          * Returns the number of rows occupied by the <code>Accessible</code>
7430          * at a specified row and column in the table.
7431          *
7432          * @return the number of rows occupied by the <code>Accessible</code>
7433          *     at a specified row and column in the table
7434          * @since 1.3
7435          */
7436         public int getAccessibleRowExtentAt(int r, int c) {
7437             return 1;
7438         }
7439 
7440         /**
7441          * Returns the number of columns occupied by the
7442          * <code>Accessible</code> at a given (row, column).
7443          *
7444          * @return the number of columns occupied by the <code>Accessible</code>
7445          *     at a specified row and column in the table
7446          * @since 1.3
7447          */
7448         public int getAccessibleColumnExtentAt(int r, int c) {
7449             return 1;
7450         }
7451 
7452         /**
7453          * Returns the row headers as an <code>AccessibleTable</code>.
7454          *
7455          * @return an <code>AccessibleTable</code> representing the row
7456          * headers
7457          * @since 1.3
7458          */
7459         public AccessibleTable getAccessibleRowHeader() {
7460             // row headers are not supported
7461             return null;
7462         }
7463 
7464         /**
7465          * Sets the row headers as an <code>AccessibleTable</code>.
7466          *
7467          * @param a an <code>AccessibleTable</code> representing the row
7468          *  headers
7469          * @since 1.3
7470          */
7471         public void setAccessibleRowHeader(AccessibleTable a) {
7472             // row headers are not supported
7473         }
7474 
7475         /**
7476          * Returns the column headers as an <code>AccessibleTable</code>.
7477          *
7478          *  @return an <code>AccessibleTable</code> representing the column
7479          *          headers, or <code>null</code> if the table header is
7480          *          <code>null</code>
7481          * @since 1.3
7482          */
7483         public AccessibleTable getAccessibleColumnHeader() {
7484             JTableHeader header = JTable.this.getTableHeader();
7485             return header == null ? null : new AccessibleTableHeader(header);
7486         }
7487 
7488         /*
7489          * Private class representing a table column header
7490          */
7491         private class AccessibleTableHeader implements AccessibleTable {
7492             private JTableHeader header;
7493             private TableColumnModel headerModel;
7494 
7495             AccessibleTableHeader(JTableHeader header) {
7496                 this.header = header;
7497                 this.headerModel = header.getColumnModel();
7498             }
7499 
7500             /**
7501              * Returns the caption for the table.
7502              *
7503              * @return the caption for the table
7504              */
7505             public Accessible getAccessibleCaption() { return null; }
7506 
7507 
7508             /**
7509              * Sets the caption for the table.
7510              *
7511              * @param a the caption for the table
7512              */
7513             public void setAccessibleCaption(Accessible a) {}
7514 
7515             /**
7516              * Returns the summary description of the table.
7517              *
7518              * @return the summary description of the table
7519              */
7520             public Accessible getAccessibleSummary() { return null; }
7521 
7522             /**
7523              * Sets the summary description of the table
7524              *
7525              * @param a the summary description of the table
7526              */
7527             public void setAccessibleSummary(Accessible a) {}
7528 
7529             /**
7530              * Returns the number of rows in the table.
7531              *
7532              * @return the number of rows in the table
7533              */
7534             public int getAccessibleRowCount() { return 1; }
7535 
7536             /**
7537              * Returns the number of columns in the table.
7538              *
7539              * @return the number of columns in the table
7540              */
7541             public int getAccessibleColumnCount() {
7542                 return headerModel.getColumnCount();
7543             }
7544 
7545             /**
7546              * Returns the Accessible at a specified row and column
7547              * in the table.
7548              *
7549              * @param row zero-based row of the table
7550              * @param column zero-based column of the table
7551              * @return the Accessible at the specified row and column
7552              */
7553             public Accessible getAccessibleAt(int row, int column) {
7554 
7555 
7556                 // TIGER - 4715503
7557                 TableColumn aColumn = headerModel.getColumn(column);
7558                 TableCellRenderer renderer = aColumn.getHeaderRenderer();
7559                 if (renderer == null) {
7560                     renderer = header.getDefaultRenderer();
7561                 }
7562                 Component component = renderer.getTableCellRendererComponent(
7563                                   header.getTable(),
7564                                   aColumn.getHeaderValue(), false, false,
7565                                   -1, column);
7566 
7567                 return new AccessibleJTableHeaderCell(row, column,
7568                                                       JTable.this.getTableHeader(),
7569                                                       component);
7570             }
7571 
7572             /**
7573              * Returns the number of rows occupied by the Accessible at
7574              * a specified row and column in the table.
7575              *
7576              * @return the number of rows occupied by the Accessible at a
7577              * given specified (row, column)
7578              */
7579             public int getAccessibleRowExtentAt(int r, int c) { return 1; }
7580 
7581             /**
7582              * Returns the number of columns occupied by the Accessible at
7583              * a specified row and column in the table.
7584              *
7585              * @return the number of columns occupied by the Accessible at a
7586              * given specified row and column
7587              */
7588             public int getAccessibleColumnExtentAt(int r, int c) { return 1; }
7589 
7590             /**
7591              * Returns the row headers as an AccessibleTable.
7592              *
7593              * @return an AccessibleTable representing the row
7594              * headers
7595              */
7596             public AccessibleTable getAccessibleRowHeader() { return null; }
7597 
7598             /**
7599              * Sets the row headers.
7600              *
7601              * @param table an AccessibleTable representing the
7602              * row headers
7603              */
7604             public void setAccessibleRowHeader(AccessibleTable table) {}
7605 
7606             /**
7607              * Returns the column headers as an AccessibleTable.
7608              *
7609              * @return an AccessibleTable representing the column
7610              * headers
7611              */
7612             public AccessibleTable getAccessibleColumnHeader() { return null; }
7613 
7614             /**
7615              * Sets the column headers.
7616              *
7617              * @param table an AccessibleTable representing the
7618              * column headers
7619              * @since 1.3
7620              */
7621             public void setAccessibleColumnHeader(AccessibleTable table) {}
7622 
7623             /**
7624              * Returns the description of the specified row in the table.
7625              *
7626              * @param r zero-based row of the table
7627              * @return the description of the row
7628              * @since 1.3
7629              */
7630             public Accessible getAccessibleRowDescription(int r) { return null; }
7631 
7632             /**
7633              * Sets the description text of the specified row of the table.
7634              *
7635              * @param r zero-based row of the table
7636              * @param a the description of the row
7637              * @since 1.3
7638              */
7639             public void setAccessibleRowDescription(int r, Accessible a) {}
7640 
7641             /**
7642              * Returns the description text of the specified column in the table.
7643              *
7644              * @param c zero-based column of the table
7645              * @return the text description of the column
7646              * @since 1.3
7647              */
7648             public Accessible getAccessibleColumnDescription(int c) { return null; }
7649 
7650             /**
7651              * Sets the description text of the specified column in the table.
7652              *
7653              * @param c zero-based column of the table
7654              * @param a the text description of the column
7655              * @since 1.3
7656              */
7657             public void setAccessibleColumnDescription(int c, Accessible a) {}
7658 
7659             /**
7660              * Returns a boolean value indicating whether the accessible at
7661              * a specified row and column is selected.
7662              *
7663              * @param r zero-based row of the table
7664              * @param c zero-based column of the table
7665              * @return the boolean value true if the accessible at the
7666              * row and column is selected. Otherwise, the boolean value
7667              * false
7668              * @since 1.3
7669              */
7670             public boolean isAccessibleSelected(int r, int c) { return false; }
7671 
7672             /**
7673              * Returns a boolean value indicating whether the specified row
7674              * is selected.
7675              *
7676              * @param r zero-based row of the table
7677              * @return the boolean value true if the specified row is selected.
7678              * Otherwise, false.
7679              * @since 1.3
7680              */
7681             public boolean isAccessibleRowSelected(int r) { return false; }
7682 
7683             /**
7684              * Returns a boolean value indicating whether the specified column
7685              * is selected.
7686              *
7687              * @param r zero-based column of the table
7688              * @return the boolean value true if the specified column is selected.
7689              * Otherwise, false.
7690              * @since 1.3
7691              */
7692             public boolean isAccessibleColumnSelected(int c) { return false; }
7693 
7694             /**
7695              * Returns the selected rows in a table.
7696              *
7697              * @return an array of selected rows where each element is a
7698              * zero-based row of the table
7699              * @since 1.3
7700              */
7701             public int [] getSelectedAccessibleRows() { return new int[0]; }
7702 
7703             /**
7704              * Returns the selected columns in a table.
7705              *
7706              * @return an array of selected columns where each element is a
7707              * zero-based column of the table
7708              * @since 1.3
7709              */
7710             public int [] getSelectedAccessibleColumns() { return new int[0]; }
7711         }
7712 
7713 
7714         /**
7715          * Sets the column headers as an <code>AccessibleTable</code>.
7716          *
7717          * @param a an <code>AccessibleTable</code> representing the
7718          * column headers
7719          * @since 1.3
7720          */
7721         public void setAccessibleColumnHeader(AccessibleTable a) {
7722             // XXX not implemented
7723         }
7724 
7725         /**
7726          * Returns the description of the specified row in the table.
7727          *
7728          * @param r zero-based row of the table
7729          * @return the description of the row
7730          * @since 1.3
7731          */
7732         public Accessible getAccessibleRowDescription(int r) {
7733             if (r < 0 || r >= getAccessibleRowCount()) {
7734                 throw new IllegalArgumentException(Integer.toString(r));
7735             }
7736             if (rowDescription == null) {
7737                 return null;
7738             } else {
7739                 return rowDescription[r];
7740             }
7741         }
7742 
7743         /**
7744          * Sets the description text of the specified row of the table.
7745          *
7746          * @param r zero-based row of the table
7747          * @param a the description of the row
7748          * @since 1.3
7749          */
7750         public void setAccessibleRowDescription(int r, Accessible a) {
7751             if (r < 0 || r >= getAccessibleRowCount()) {
7752                 throw new IllegalArgumentException(Integer.toString(r));
7753             }
7754             if (rowDescription == null) {
7755                 int numRows = getAccessibleRowCount();
7756                 rowDescription = new Accessible[numRows];
7757             }
7758             rowDescription[r] = a;
7759         }
7760 
7761         /**
7762          * Returns the description of the specified column in the table.
7763          *
7764          * @param c zero-based column of the table
7765          * @return the description of the column
7766          * @since 1.3
7767          */
7768         public Accessible getAccessibleColumnDescription(int c) {
7769             if (c < 0 || c >= getAccessibleColumnCount()) {
7770                 throw new IllegalArgumentException(Integer.toString(c));
7771             }
7772             if (columnDescription == null) {
7773                 return null;
7774             } else {
7775                 return columnDescription[c];
7776             }
7777         }
7778 
7779         /**
7780          * Sets the description text of the specified column of the table.
7781          *
7782          * @param c zero-based column of the table
7783          * @param a the description of the column
7784          * @since 1.3
7785          */
7786         public void setAccessibleColumnDescription(int c, Accessible a) {
7787             if (c < 0 || c >= getAccessibleColumnCount()) {
7788                 throw new IllegalArgumentException(Integer.toString(c));
7789             }
7790             if (columnDescription == null) {
7791                 int numColumns = getAccessibleColumnCount();
7792                 columnDescription = new Accessible[numColumns];
7793             }
7794             columnDescription[c] = a;
7795         }
7796 
7797         /**
7798          * Returns a boolean value indicating whether the accessible at a
7799          * given (row, column) is selected.
7800          *
7801          * @param r zero-based row of the table
7802          * @param c zero-based column of the table
7803          * @return the boolean value true if the accessible at (row, column)
7804          *     is selected; otherwise, the boolean value false
7805          * @since 1.3
7806          */
7807         public boolean isAccessibleSelected(int r, int c) {
7808             return JTable.this.isCellSelected(r, c);
7809         }
7810 
7811         /**
7812          * Returns a boolean value indicating whether the specified row
7813          * is selected.
7814          *
7815          * @param r zero-based row of the table
7816          * @return the boolean value true if the specified row is selected;
7817          *     otherwise, false
7818          * @since 1.3
7819          */
7820         public boolean isAccessibleRowSelected(int r) {
7821             return JTable.this.isRowSelected(r);
7822         }
7823 
7824         /**
7825          * Returns a boolean value indicating whether the specified column
7826          * is selected.
7827          *
7828          * @param c zero-based column of the table
7829          * @return the boolean value true if the specified column is selected;
7830          *     otherwise, false
7831          * @since 1.3
7832          */
7833         public boolean isAccessibleColumnSelected(int c) {
7834             return JTable.this.isColumnSelected(c);
7835         }
7836 
7837         /**
7838          * Returns the selected rows in a table.
7839          *
7840          * @return an array of selected rows where each element is a
7841          *     zero-based row of the table
7842          * @since 1.3
7843          */
7844         public int [] getSelectedAccessibleRows() {
7845             return JTable.this.getSelectedRows();
7846         }
7847 
7848         /**
7849          * Returns the selected columns in a table.
7850          *
7851          * @return an array of selected columns where each element is a
7852          *     zero-based column of the table
7853          * @since 1.3
7854          */
7855         public int [] getSelectedAccessibleColumns() {
7856             return JTable.this.getSelectedColumns();
7857         }
7858 
7859         /**
7860          * Returns the row at a given index into the table.
7861          *
7862          * @param i zero-based index into the table
7863          * @return the row at a given index
7864          * @since 1.3
7865          */
7866         public int getAccessibleRowAtIndex(int i) {
7867             int columnCount = getAccessibleColumnCount();
7868             if (columnCount == 0) {
7869                 return -1;
7870             } else {
7871                 return (i / columnCount);
7872             }
7873         }
7874 
7875         /**
7876          * Returns the column at a given index into the table.
7877          *
7878          * @param i zero-based index into the table
7879          * @return the column at a given index
7880          * @since 1.3
7881          */
7882         public int getAccessibleColumnAtIndex(int i) {
7883             int columnCount = getAccessibleColumnCount();
7884             if (columnCount == 0) {
7885                 return -1;
7886             } else {
7887                 return (i % columnCount);
7888             }
7889         }
7890 
7891         /**
7892          * Returns the index at a given (row, column) in the table.
7893          *
7894          * @param r zero-based row of the table
7895          * @param c zero-based column of the table
7896          * @return the index into the table
7897          * @since 1.3
7898          */
7899         public int getAccessibleIndexAt(int r, int c) {
7900             return ((r * getAccessibleColumnCount()) + c);
7901         }
7902 
7903         // end of AccessibleTable implementation --------------------
7904 
7905         /**
7906          * The class provides an implementation of the Java Accessibility
7907          * API appropriate to table cells.
7908          */
7909         protected class AccessibleJTableCell extends AccessibleContext
7910             implements Accessible, AccessibleComponent {
7911 
7912             private JTable parent;
7913             private int row;
7914             private int column;
7915             private int index;
7916 
7917             /**
7918              *  Constructs an <code>AccessibleJTableHeaderEntry</code>.
7919              * @since 1.4
7920              */
7921             public AccessibleJTableCell(JTable t, int r, int c, int i) {
7922                 parent = t;
7923                 row = r;
7924                 column = c;
7925                 index = i;
7926                 this.setAccessibleParent(parent);
7927             }
7928 
7929             /**
7930              * Gets the <code>AccessibleContext</code> associated with this
7931              * component. In the implementation of the Java Accessibility
7932              * API for this class, return this object, which is its own
7933              * <code>AccessibleContext</code>.
7934              *
7935              * @return this object
7936              */
7937             public AccessibleContext getAccessibleContext() {
7938                 return this;
7939             }
7940 
7941             /**
7942              * Gets the AccessibleContext for the table cell renderer.
7943              *
7944              * @return the <code>AccessibleContext</code> for the table
7945              * cell renderer if one exists;
7946              * otherwise, returns <code>null</code>.
7947              * @since 1.6
7948              */
7949             protected AccessibleContext getCurrentAccessibleContext() {
7950                 TableColumn aColumn = getColumnModel().getColumn(column);
7951                 TableCellRenderer renderer = aColumn.getCellRenderer();
7952                 if (renderer == null) {
7953                     Class<?> columnClass = getColumnClass(column);
7954                     renderer = getDefaultRenderer(columnClass);
7955                 }
7956                 Component component = renderer.getTableCellRendererComponent(
7957                                   JTable.this, getValueAt(row, column),
7958                                   false, false, row, column);
7959                 if (component instanceof Accessible) {
7960                     return component.getAccessibleContext();
7961                 } else {
7962                     return null;
7963                 }
7964             }
7965 
7966             /**
7967              * Gets the table cell renderer component.
7968              *
7969              * @return the table cell renderer component if one exists;
7970              * otherwise, returns <code>null</code>.
7971              * @since 1.6
7972              */
7973             protected Component getCurrentComponent() {
7974                 TableColumn aColumn = getColumnModel().getColumn(column);
7975                 TableCellRenderer renderer = aColumn.getCellRenderer();
7976                 if (renderer == null) {
7977                     Class<?> columnClass = getColumnClass(column);
7978                     renderer = getDefaultRenderer(columnClass);
7979                 }
7980                 return renderer.getTableCellRendererComponent(
7981                                   JTable.this, null, false, false,
7982                                   row, column);
7983             }
7984 
7985         // AccessibleContext methods
7986 
7987             /**
7988              * Gets the accessible name of this object.
7989              *
7990              * @return the localized name of the object; <code>null</code>
7991              *     if this object does not have a name
7992              */
7993             public String getAccessibleName() {
7994                 AccessibleContext ac = getCurrentAccessibleContext();
7995                 if (ac != null) {
7996                     String name = ac.getAccessibleName();
7997                     if ((name != null) && (name != "")) {
7998                         // return the cell renderer's AccessibleName
7999                         return name;
8000                     }
8001                 }
8002                 if ((accessibleName != null) && (accessibleName != "")) {
8003                     return accessibleName;
8004                 } else {
8005                     // fall back to the client property
8006                     return (String)getClientProperty(AccessibleContext.ACCESSIBLE_NAME_PROPERTY);
8007                 }
8008             }
8009 
8010             /**
8011              * Sets the localized accessible name of this object.
8012              *
8013              * @param s the new localized name of the object
8014              */
8015             public void setAccessibleName(String s) {
8016                 AccessibleContext ac = getCurrentAccessibleContext();
8017                 if (ac != null) {
8018                     ac.setAccessibleName(s);
8019                 } else {
8020                     super.setAccessibleName(s);
8021                 }
8022             }
8023 
8024             //
8025             // *** should check toolTip text for desc. (needs MouseEvent)
8026             //
8027             /**
8028              * Gets the accessible description of this object.
8029              *
8030              * @return the localized description of the object;
8031              *     <code>null</code> if this object does not have
8032              *     a description
8033              */
8034             public String getAccessibleDescription() {
8035                 AccessibleContext ac = getCurrentAccessibleContext();
8036                 if (ac != null) {
8037                     return ac.getAccessibleDescription();
8038                 } else {
8039                     return super.getAccessibleDescription();
8040                 }
8041             }
8042 
8043             /**
8044              * Sets the accessible description of this object.
8045              *
8046              * @param s the new localized description of the object
8047              */
8048             public void setAccessibleDescription(String s) {
8049                 AccessibleContext ac = getCurrentAccessibleContext();
8050                 if (ac != null) {
8051                     ac.setAccessibleDescription(s);
8052                 } else {
8053                     super.setAccessibleDescription(s);
8054                 }
8055             }
8056 
8057             /**
8058              * Gets the role of this object.
8059              *
8060              * @return an instance of <code>AccessibleRole</code>
8061              *      describing the role of the object
8062              * @see AccessibleRole
8063              */
8064             public AccessibleRole getAccessibleRole() {
8065                 AccessibleContext ac = getCurrentAccessibleContext();
8066                 if (ac != null) {
8067                     return ac.getAccessibleRole();
8068                 } else {
8069                     return AccessibleRole.UNKNOWN;
8070                 }
8071             }
8072 
8073             /**
8074              * Gets the state set of this object.
8075              *
8076              * @return an instance of <code>AccessibleStateSet</code>
8077              *     containing the current state set of the object
8078              * @see AccessibleState
8079              */
8080             public AccessibleStateSet getAccessibleStateSet() {
8081                 AccessibleContext ac = getCurrentAccessibleContext();
8082                 AccessibleStateSet as = null;
8083 
8084                 if (ac != null) {
8085                     as = ac.getAccessibleStateSet();
8086                 }
8087                 if (as == null) {
8088                     as = new AccessibleStateSet();
8089                 }
8090                 Rectangle rjt = JTable.this.getVisibleRect();
8091                 Rectangle rcell = JTable.this.getCellRect(row, column, false);
8092                 if (rjt.intersects(rcell)) {
8093                     as.add(AccessibleState.SHOWING);
8094                 } else {
8095                     if (as.contains(AccessibleState.SHOWING)) {
8096                          as.remove(AccessibleState.SHOWING);
8097                     }
8098                 }
8099                 if (parent.isCellSelected(row, column)) {
8100                     as.add(AccessibleState.SELECTED);
8101                 } else if (as.contains(AccessibleState.SELECTED)) {
8102                     as.remove(AccessibleState.SELECTED);
8103                 }
8104                 if ((row == getSelectedRow()) && (column == getSelectedColumn())) {
8105                     as.add(AccessibleState.ACTIVE);
8106                 }
8107                 as.add(AccessibleState.TRANSIENT);
8108                 return as;
8109             }
8110 
8111             /**
8112              * Gets the <code>Accessible</code> parent of this object.
8113              *
8114              * @return the Accessible parent of this object;
8115              *     <code>null</code> if this object does not
8116              *     have an <code>Accessible</code> parent
8117              */
8118             public Accessible getAccessibleParent() {
8119                 return parent;
8120             }
8121 
8122             /**
8123              * Gets the index of this object in its accessible parent.
8124              *
8125              * @return the index of this object in its parent; -1 if this
8126              *     object does not have an accessible parent
8127              * @see #getAccessibleParent
8128              */
8129             public int getAccessibleIndexInParent() {
8130                 return index;
8131             }
8132 
8133             /**
8134              * Returns the number of accessible children in the object.
8135              *
8136              * @return the number of accessible children in the object
8137              */
8138             public int getAccessibleChildrenCount() {
8139                 AccessibleContext ac = getCurrentAccessibleContext();
8140                 if (ac != null) {
8141                     return ac.getAccessibleChildrenCount();
8142                 } else {
8143                     return 0;
8144                 }
8145             }
8146 
8147             /**
8148              * Returns the specified <code>Accessible</code> child of the
8149              * object.
8150              *
8151              * @param i zero-based index of child
8152              * @return the <code>Accessible</code> child of the object
8153              */
8154             public Accessible getAccessibleChild(int i) {
8155                 AccessibleContext ac = getCurrentAccessibleContext();
8156                 if (ac != null) {
8157                     Accessible accessibleChild = ac.getAccessibleChild(i);
8158                     ac.setAccessibleParent(this);
8159                     return accessibleChild;
8160                 } else {
8161                     return null;
8162                 }
8163             }
8164 
8165             /**
8166              * Gets the locale of the component. If the component
8167              * does not have a locale, then the locale of its parent
8168              * is returned.
8169              *
8170              * @return this component's locale; if this component does
8171              *    not have a locale, the locale of its parent is returned
8172              * @exception IllegalComponentStateException if the
8173              *    <code>Component</code> does not have its own locale
8174              *    and has not yet been added to a containment hierarchy
8175              *    such that the locale can be determined from the
8176              *    containing parent
8177              * @see #setLocale
8178              */
8179             public Locale getLocale() {
8180                 AccessibleContext ac = getCurrentAccessibleContext();
8181                 if (ac != null) {
8182                     return ac.getLocale();
8183                 } else {
8184                     return null;
8185                 }
8186             }
8187 
8188             /**
8189              * Adds a <code>PropertyChangeListener</code> to the listener list.
8190              * The listener is registered for all properties.
8191              *
8192              * @param l  the <code>PropertyChangeListener</code>
8193              *     to be added
8194              */
8195             public void addPropertyChangeListener(PropertyChangeListener l) {
8196                 AccessibleContext ac = getCurrentAccessibleContext();
8197                 if (ac != null) {
8198                     ac.addPropertyChangeListener(l);
8199                 } else {
8200                     super.addPropertyChangeListener(l);
8201                 }
8202             }
8203 
8204             /**
8205              * Removes a <code>PropertyChangeListener</code> from the
8206              * listener list. This removes a <code>PropertyChangeListener</code>
8207              * that was registered for all properties.
8208              *
8209              * @param l  the <code>PropertyChangeListener</code>
8210              *    to be removed
8211              */
8212             public void removePropertyChangeListener(PropertyChangeListener l) {
8213                 AccessibleContext ac = getCurrentAccessibleContext();
8214                 if (ac != null) {
8215                     ac.removePropertyChangeListener(l);
8216                 } else {
8217                     super.removePropertyChangeListener(l);
8218                 }
8219             }
8220 
8221             /**
8222              * Gets the <code>AccessibleAction</code> associated with this
8223              * object if one exists.  Otherwise returns <code>null</code>.
8224              *
8225              * @return the <code>AccessibleAction</code>, or <code>null</code>
8226              */
8227             public AccessibleAction getAccessibleAction() {
8228                 return getCurrentAccessibleContext().getAccessibleAction();
8229             }
8230 
8231             /**
8232              * Gets the <code>AccessibleComponent</code> associated with
8233              * this object if one exists.  Otherwise returns <code>null</code>.
8234              *
8235              * @return the <code>AccessibleComponent</code>, or
8236              *    <code>null</code>
8237              */
8238             public AccessibleComponent getAccessibleComponent() {
8239                 return this; // to override getBounds()
8240             }
8241 
8242             /**
8243              * Gets the <code>AccessibleSelection</code> associated with
8244              * this object if one exists.  Otherwise returns <code>null</code>.
8245              *
8246              * @return the <code>AccessibleSelection</code>, or
8247              *    <code>null</code>
8248              */
8249             public AccessibleSelection getAccessibleSelection() {
8250                 return getCurrentAccessibleContext().getAccessibleSelection();
8251             }
8252 
8253             /**
8254              * Gets the <code>AccessibleText</code> associated with this
8255              * object if one exists.  Otherwise returns <code>null</code>.
8256              *
8257              * @return the <code>AccessibleText</code>, or <code>null</code>
8258              */
8259             public AccessibleText getAccessibleText() {
8260                 return getCurrentAccessibleContext().getAccessibleText();
8261             }
8262 
8263             /**
8264              * Gets the <code>AccessibleValue</code> associated with
8265              * this object if one exists.  Otherwise returns <code>null</code>.
8266              *
8267              * @return the <code>AccessibleValue</code>, or <code>null</code>
8268              */
8269             public AccessibleValue getAccessibleValue() {
8270                 return getCurrentAccessibleContext().getAccessibleValue();
8271             }
8272 
8273 
8274         // AccessibleComponent methods
8275 
8276             /**
8277              * Gets the background color of this object.
8278              *
8279              * @return the background color, if supported, of the object;
8280              *     otherwise, <code>null</code>
8281              */
8282             public Color getBackground() {
8283                 AccessibleContext ac = getCurrentAccessibleContext();
8284                 if (ac instanceof AccessibleComponent) {
8285                     return ((AccessibleComponent) ac).getBackground();
8286                 } else {
8287                     Component c = getCurrentComponent();
8288                     if (c != null) {
8289                         return c.getBackground();
8290                     } else {
8291                         return null;
8292                     }
8293                 }
8294             }
8295 
8296             /**
8297              * Sets the background color of this object.
8298              *
8299              * @param c the new <code>Color</code> for the background
8300              */
8301             public void setBackground(Color c) {
8302                 AccessibleContext ac = getCurrentAccessibleContext();
8303                 if (ac instanceof AccessibleComponent) {
8304                     ((AccessibleComponent) ac).setBackground(c);
8305                 } else {
8306                     Component cp = getCurrentComponent();
8307                     if (cp != null) {
8308                         cp.setBackground(c);
8309                     }
8310                 }
8311             }
8312 
8313             /**
8314              * Gets the foreground color of this object.
8315              *
8316              * @return the foreground color, if supported, of the object;
8317              *     otherwise, <code>null</code>
8318              */
8319             public Color getForeground() {
8320                 AccessibleContext ac = getCurrentAccessibleContext();
8321                 if (ac instanceof AccessibleComponent) {
8322                     return ((AccessibleComponent) ac).getForeground();
8323                 } else {
8324                     Component c = getCurrentComponent();
8325                     if (c != null) {
8326                         return c.getForeground();
8327                     } else {
8328                         return null;
8329                     }
8330                 }
8331             }
8332 
8333             /**
8334              * Sets the foreground color of this object.
8335              *
8336              * @param c the new <code>Color</code> for the foreground
8337              */
8338             public void setForeground(Color c) {
8339                 AccessibleContext ac = getCurrentAccessibleContext();
8340                 if (ac instanceof AccessibleComponent) {
8341                     ((AccessibleComponent) ac).setForeground(c);
8342                 } else {
8343                     Component cp = getCurrentComponent();
8344                     if (cp != null) {
8345                         cp.setForeground(c);
8346                     }
8347                 }
8348             }
8349 
8350             /**
8351              * Gets the <code>Cursor</code> of this object.
8352              *
8353              * @return the <code>Cursor</code>, if supported,
8354              *    of the object; otherwise, <code>null</code>
8355              */
8356             public Cursor getCursor() {
8357                 AccessibleContext ac = getCurrentAccessibleContext();
8358                 if (ac instanceof AccessibleComponent) {
8359                     return ((AccessibleComponent) ac).getCursor();
8360                 } else {
8361                     Component c = getCurrentComponent();
8362                     if (c != null) {
8363                         return c.getCursor();
8364                     } else {
8365                         Accessible ap = getAccessibleParent();
8366                         if (ap instanceof AccessibleComponent) {
8367                             return ((AccessibleComponent) ap).getCursor();
8368                         } else {
8369                             return null;
8370                         }
8371                     }
8372                 }
8373             }
8374 
8375             /**
8376              * Sets the <code>Cursor</code> of this object.
8377              *
8378              * @param c the new <code>Cursor</code> for the object
8379              */
8380             public void setCursor(Cursor c) {
8381                 AccessibleContext ac = getCurrentAccessibleContext();
8382                 if (ac instanceof AccessibleComponent) {
8383                     ((AccessibleComponent) ac).setCursor(c);
8384                 } else {
8385                     Component cp = getCurrentComponent();
8386                     if (cp != null) {
8387                         cp.setCursor(c);
8388                     }
8389                 }
8390             }
8391 
8392             /**
8393              * Gets the <code>Font</code> of this object.
8394              *
8395              * @return the <code>Font</code>,if supported,
8396              *   for the object; otherwise, <code>null</code>
8397              */
8398             public Font getFont() {
8399                 AccessibleContext ac = getCurrentAccessibleContext();
8400                 if (ac instanceof AccessibleComponent) {
8401                     return ((AccessibleComponent) ac).getFont();
8402                 } else {
8403                     Component c = getCurrentComponent();
8404                     if (c != null) {
8405                         return c.getFont();
8406                     } else {
8407                         return null;
8408                     }
8409                 }
8410             }
8411 
8412             /**
8413              * Sets the <code>Font</code> of this object.
8414              *
8415              * @param f the new <code>Font</code> for the object
8416              */
8417             public void setFont(Font f) {
8418                 AccessibleContext ac = getCurrentAccessibleContext();
8419                 if (ac instanceof AccessibleComponent) {
8420                     ((AccessibleComponent) ac).setFont(f);
8421                 } else {
8422                     Component c = getCurrentComponent();
8423                     if (c != null) {
8424                         c.setFont(f);
8425                     }
8426                 }
8427             }
8428 
8429             /**
8430              * Gets the <code>FontMetrics</code> of this object.
8431              *
8432              * @param f the <code>Font</code>
8433              * @return the <code>FontMetrics</code> object, if supported;
8434              *    otherwise <code>null</code>
8435              * @see #getFont
8436              */
8437             public FontMetrics getFontMetrics(Font f) {
8438                 AccessibleContext ac = getCurrentAccessibleContext();
8439                 if (ac instanceof AccessibleComponent) {
8440                     return ((AccessibleComponent) ac).getFontMetrics(f);
8441                 } else {
8442                     Component c = getCurrentComponent();
8443                     if (c != null) {
8444                         return c.getFontMetrics(f);
8445                     } else {
8446                         return null;
8447                     }
8448                 }
8449             }
8450 
8451             /**
8452              * Determines if the object is enabled.
8453              *
8454              * @return true if object is enabled; otherwise, false
8455              */
8456             public boolean isEnabled() {
8457                 AccessibleContext ac = getCurrentAccessibleContext();
8458                 if (ac instanceof AccessibleComponent) {
8459                     return ((AccessibleComponent) ac).isEnabled();
8460                 } else {
8461                     Component c = getCurrentComponent();
8462                     if (c != null) {
8463                         return c.isEnabled();
8464                     } else {
8465                         return false;
8466                     }
8467                 }
8468             }
8469 
8470             /**
8471              * Sets the enabled state of the object.
8472              *
8473              * @param b if true, enables this object; otherwise, disables it
8474              */
8475             public void setEnabled(boolean b) {
8476                 AccessibleContext ac = getCurrentAccessibleContext();
8477                 if (ac instanceof AccessibleComponent) {
8478                     ((AccessibleComponent) ac).setEnabled(b);
8479                 } else {
8480                     Component c = getCurrentComponent();
8481                     if (c != null) {
8482                         c.setEnabled(b);
8483                     }
8484                 }
8485             }
8486 
8487             /**
8488              * Determines if this object is visible.  Note: this means that the
8489              * object intends to be visible; however, it may not in fact be
8490              * showing on the screen because one of the objects that this object
8491              * is contained by is not visible.  To determine if an object is
8492              * showing on the screen, use <code>isShowing</code>.
8493              *
8494              * @return true if object is visible; otherwise, false
8495              */
8496             public boolean isVisible() {
8497                 AccessibleContext ac = getCurrentAccessibleContext();
8498                 if (ac instanceof AccessibleComponent) {
8499                     return ((AccessibleComponent) ac).isVisible();
8500                 } else {
8501                     Component c = getCurrentComponent();
8502                     if (c != null) {
8503                         return c.isVisible();
8504                     } else {
8505                         return false;
8506                     }
8507                 }
8508             }
8509 
8510             /**
8511              * Sets the visible state of the object.
8512              *
8513              * @param b if true, shows this object; otherwise, hides it
8514              */
8515             public void setVisible(boolean b) {
8516                 AccessibleContext ac = getCurrentAccessibleContext();
8517                 if (ac instanceof AccessibleComponent) {
8518                     ((AccessibleComponent) ac).setVisible(b);
8519                 } else {
8520                     Component c = getCurrentComponent();
8521                     if (c != null) {
8522                         c.setVisible(b);
8523                     }
8524                 }
8525             }
8526 
8527             /**
8528              * Determines if the object is showing.  This is determined
8529              * by checking the visibility of the object and ancestors
8530              * of the object.  Note: this will return true even if the
8531              * object is obscured by another (for example,
8532              * it happens to be underneath a menu that was pulled down).
8533              *
8534              * @return true if the object is showing; otherwise, false
8535              */
8536             public boolean isShowing() {
8537                 AccessibleContext ac = getCurrentAccessibleContext();
8538                 if (ac instanceof AccessibleComponent) {
8539                     if (ac.getAccessibleParent() != null) {
8540                         return ((AccessibleComponent) ac).isShowing();
8541                     } else {
8542                         // Fixes 4529616 - AccessibleJTableCell.isShowing()
8543                         // returns false when the cell on the screen
8544                         // if no parent
8545                         return isVisible();
8546                     }
8547                 } else {
8548                     Component c = getCurrentComponent();
8549                     if (c != null) {
8550                         return c.isShowing();
8551                     } else {
8552                         return false;
8553                     }
8554                 }
8555             }
8556 
8557             /**
8558              * Checks whether the specified point is within this
8559              * object's bounds, where the point's x and y coordinates
8560              * are defined to be relative to the coordinate system of
8561              * the object.
8562              *
8563              * @param p the <code>Point</code> relative to the
8564              *    coordinate system of the object
8565              * @return true if object contains <code>Point</code>;
8566              *    otherwise false
8567              */
8568             public boolean contains(Point p) {
8569                 AccessibleContext ac = getCurrentAccessibleContext();
8570                 if (ac instanceof AccessibleComponent) {
8571                     Rectangle r = ((AccessibleComponent) ac).getBounds();
8572                     return r.contains(p);
8573                 } else {
8574                     Component c = getCurrentComponent();
8575                     if (c != null) {
8576                         Rectangle r = c.getBounds();
8577                         return r.contains(p);
8578                     } else {
8579                         return getBounds().contains(p);
8580                     }
8581                 }
8582             }
8583 
8584             /**
8585              * Returns the location of the object on the screen.
8586              *
8587              * @return location of object on screen -- can be
8588              *    <code>null</code> if this object is not on the screen
8589              */
8590             public Point getLocationOnScreen() {
8591                 if (parent != null) {
8592                     Point parentLocation = parent.getLocationOnScreen();
8593                     Point componentLocation = getLocation();
8594                     componentLocation.translate(parentLocation.x, parentLocation.y);
8595                     return componentLocation;
8596                 } else {
8597                     return null;
8598                 }
8599             }
8600 
8601             /**
8602              * Gets the location of the object relative to the parent
8603              * in the form of a point specifying the object's
8604              * top-left corner in the screen's coordinate space.
8605              *
8606              * @return an instance of <code>Point</code> representing
8607              *    the top-left corner of the object's bounds in the
8608              *    coordinate space of the screen; <code>null</code> if
8609              *    this object or its parent are not on the screen
8610              */
8611             public Point getLocation() {
8612                 if (parent != null) {
8613                     Rectangle r = parent.getCellRect(row, column, false);
8614                     if (r != null) {
8615                         return r.getLocation();
8616                     }
8617                 }
8618                 return null;
8619             }
8620 
8621             /**
8622              * Sets the location of the object relative to the parent.
8623              */
8624             public void setLocation(Point p) {
8625 //              if ((parent != null)  && (parent.contains(p))) {
8626 //                  ensureIndexIsVisible(indexInParent);
8627 //              }
8628             }
8629 
8630             public Rectangle getBounds() {
8631                 if (parent != null) {
8632                     return parent.getCellRect(row, column, false);
8633                 } else {
8634                     return null;
8635                 }
8636             }
8637 
8638             public void setBounds(Rectangle r) {
8639                 AccessibleContext ac = getCurrentAccessibleContext();
8640                 if (ac instanceof AccessibleComponent) {
8641                     ((AccessibleComponent) ac).setBounds(r);
8642                 } else {
8643                     Component c = getCurrentComponent();
8644                     if (c != null) {
8645                         c.setBounds(r);
8646                     }
8647                 }
8648             }
8649 
8650             public Dimension getSize() {
8651                 if (parent != null) {
8652                     Rectangle r = parent.getCellRect(row, column, false);
8653                     if (r != null) {
8654                         return r.getSize();
8655                     }
8656                 }
8657                 return null;
8658             }
8659 
8660             public void setSize (Dimension d) {
8661                 AccessibleContext ac = getCurrentAccessibleContext();
8662                 if (ac instanceof AccessibleComponent) {
8663                     ((AccessibleComponent) ac).setSize(d);
8664                 } else {
8665                     Component c = getCurrentComponent();
8666                     if (c != null) {
8667                         c.setSize(d);
8668                     }
8669                 }
8670             }
8671 
8672             public Accessible getAccessibleAt(Point p) {
8673                 AccessibleContext ac = getCurrentAccessibleContext();
8674                 if (ac instanceof AccessibleComponent) {
8675                     return ((AccessibleComponent) ac).getAccessibleAt(p);
8676                 } else {
8677                     return null;
8678                 }
8679             }
8680 
8681             public boolean isFocusTraversable() {
8682                 AccessibleContext ac = getCurrentAccessibleContext();
8683                 if (ac instanceof AccessibleComponent) {
8684                     return ((AccessibleComponent) ac).isFocusTraversable();
8685                 } else {
8686                     Component c = getCurrentComponent();
8687                     if (c != null) {
8688                         return c.isFocusTraversable();
8689                     } else {
8690                         return false;
8691                     }
8692                 }
8693             }
8694 
8695             public void requestFocus() {
8696                 AccessibleContext ac = getCurrentAccessibleContext();
8697                 if (ac instanceof AccessibleComponent) {
8698                     ((AccessibleComponent) ac).requestFocus();
8699                 } else {
8700                     Component c = getCurrentComponent();
8701                     if (c != null) {
8702                         c.requestFocus();
8703                     }
8704                 }
8705             }
8706 
8707             public void addFocusListener(FocusListener l) {
8708                 AccessibleContext ac = getCurrentAccessibleContext();
8709                 if (ac instanceof AccessibleComponent) {
8710                     ((AccessibleComponent) ac).addFocusListener(l);
8711                 } else {
8712                     Component c = getCurrentComponent();
8713                     if (c != null) {
8714                         c.addFocusListener(l);
8715                     }
8716                 }
8717             }
8718 
8719             public void removeFocusListener(FocusListener l) {
8720                 AccessibleContext ac = getCurrentAccessibleContext();
8721                 if (ac instanceof AccessibleComponent) {
8722                     ((AccessibleComponent) ac).removeFocusListener(l);
8723                 } else {
8724                     Component c = getCurrentComponent();
8725                     if (c != null) {
8726                         c.removeFocusListener(l);
8727                     }
8728                 }
8729             }
8730 
8731         } // inner class AccessibleJTableCell
8732 
8733         // Begin AccessibleJTableHeader ========== // TIGER - 4715503
8734 
8735         /**
8736          * This class implements accessibility for JTable header cells.
8737          */
8738         private class AccessibleJTableHeaderCell extends AccessibleContext
8739             implements Accessible, AccessibleComponent {
8740 
8741             private int row;
8742             private int column;
8743             private JTableHeader parent;
8744             private Component rendererComponent;
8745 
8746             /**
8747              * Constructs an <code>AccessibleJTableHeaderEntry</code> instance.
8748              *
8749              * @param row header cell row index
8750              * @param column header cell column index
8751              * @param parent header cell parent
8752              * @param rendererComponent component that renders the header cell
8753              */
8754             public AccessibleJTableHeaderCell(int row, int column,
8755                                               JTableHeader parent,
8756                                               Component rendererComponent) {
8757                 this.row = row;
8758                 this.column = column;
8759                 this.parent = parent;
8760                 this.rendererComponent = rendererComponent;
8761                 this.setAccessibleParent(parent);
8762             }
8763 
8764             /**
8765              * Gets the <code>AccessibleContext</code> associated with this
8766              * component. In the implementation of the Java Accessibility
8767              * API for this class, return this object, which is its own
8768              * <code>AccessibleContext</code>.
8769              *
8770              * @return this object
8771              */
8772             public AccessibleContext getAccessibleContext() {
8773                 return this;
8774             }
8775 
8776             /*
8777              * Returns the AccessibleContext for the header cell
8778              * renderer.
8779              */
8780             private AccessibleContext getCurrentAccessibleContext() {
8781                 return rendererComponent.getAccessibleContext();
8782             }
8783 
8784             /*
8785              * Returns the component that renders the header cell.
8786              */
8787             private Component getCurrentComponent() {
8788                 return rendererComponent;
8789             }
8790 
8791             // AccessibleContext methods ==========
8792 
8793             /**
8794              * Gets the accessible name of this object.
8795              *
8796              * @return the localized name of the object; <code>null</code>
8797              *     if this object does not have a name
8798              */
8799             public String getAccessibleName() {
8800                 AccessibleContext ac = getCurrentAccessibleContext();
8801                 if (ac != null) {
8802                     String name = ac.getAccessibleName();
8803                     if ((name != null) && (name != "")) {
8804                         return ac.getAccessibleName();
8805                     }
8806                 }
8807                 if ((accessibleName != null) && (accessibleName != "")) {
8808                     return accessibleName;
8809                 } else {
8810                     return null;
8811                 }
8812             }
8813 
8814             /**
8815              * Sets the localized accessible name of this object.
8816              *
8817              * @param s the new localized name of the object
8818              */
8819             public void setAccessibleName(String s) {
8820                 AccessibleContext ac = getCurrentAccessibleContext();
8821                 if (ac != null) {
8822                     ac.setAccessibleName(s);
8823                 } else {
8824                     super.setAccessibleName(s);
8825                 }
8826             }
8827 
8828             /**
8829              * Gets the accessible description of this object.
8830              *
8831              * @return the localized description of the object;
8832              *     <code>null</code> if this object does not have
8833              *     a description
8834              */
8835             public String getAccessibleDescription() {
8836                 AccessibleContext ac = getCurrentAccessibleContext();
8837                 if (ac != null) {
8838                     return ac.getAccessibleDescription();
8839                 } else {
8840                     return super.getAccessibleDescription();
8841                 }
8842             }
8843 
8844             /**
8845              * Sets the accessible description of this object.
8846              *
8847              * @param s the new localized description of the object
8848              */
8849             public void setAccessibleDescription(String s) {
8850                 AccessibleContext ac = getCurrentAccessibleContext();
8851                 if (ac != null) {
8852                     ac.setAccessibleDescription(s);
8853                 } else {
8854                     super.setAccessibleDescription(s);
8855                 }
8856             }
8857 
8858             /**
8859              * Gets the role of this object.
8860              *
8861              * @return an instance of <code>AccessibleRole</code>
8862              *      describing the role of the object
8863              * @see AccessibleRole
8864              */
8865             public AccessibleRole getAccessibleRole() {
8866                 AccessibleContext ac = getCurrentAccessibleContext();
8867                 if (ac != null) {
8868                     return ac.getAccessibleRole();
8869                 } else {
8870                     return AccessibleRole.UNKNOWN;
8871                 }
8872             }
8873 
8874             /**
8875              * Gets the state set of this object.
8876              *
8877              * @return an instance of <code>AccessibleStateSet</code>
8878              *     containing the current state set of the object
8879              * @see AccessibleState
8880              */
8881             public AccessibleStateSet getAccessibleStateSet() {
8882                 AccessibleContext ac = getCurrentAccessibleContext();
8883                 AccessibleStateSet as = null;
8884 
8885                 if (ac != null) {
8886                     as = ac.getAccessibleStateSet();
8887                 }
8888                 if (as == null) {
8889                     as = new AccessibleStateSet();
8890                 }
8891                 Rectangle rjt = JTable.this.getVisibleRect();
8892                 Rectangle rcell = JTable.this.getCellRect(row, column, false);
8893                 if (rjt.intersects(rcell)) {
8894                     as.add(AccessibleState.SHOWING);
8895                 } else {
8896                     if (as.contains(AccessibleState.SHOWING)) {
8897                          as.remove(AccessibleState.SHOWING);
8898                     }
8899                 }
8900                 if (JTable.this.isCellSelected(row, column)) {
8901                     as.add(AccessibleState.SELECTED);
8902                 } else if (as.contains(AccessibleState.SELECTED)) {
8903                     as.remove(AccessibleState.SELECTED);
8904                 }
8905                 if ((row == getSelectedRow()) && (column == getSelectedColumn())) {
8906                     as.add(AccessibleState.ACTIVE);
8907                 }
8908                 as.add(AccessibleState.TRANSIENT);
8909                 return as;
8910             }
8911 
8912             /**
8913              * Gets the <code>Accessible</code> parent of this object.
8914              *
8915              * @return the Accessible parent of this object;
8916              *     <code>null</code> if this object does not
8917              *     have an <code>Accessible</code> parent
8918              */
8919             public Accessible getAccessibleParent() {
8920                 return parent;
8921             }
8922 
8923             /**
8924              * Gets the index of this object in its accessible parent.
8925              *
8926              * @return the index of this object in its parent; -1 if this
8927              *     object does not have an accessible parent
8928              * @see #getAccessibleParent
8929              */
8930             public int getAccessibleIndexInParent() {
8931                 return column;
8932             }
8933 
8934             /**
8935              * Returns the number of accessible children in the object.
8936              *
8937              * @return the number of accessible children in the object
8938              */
8939             public int getAccessibleChildrenCount() {
8940                 AccessibleContext ac = getCurrentAccessibleContext();
8941                 if (ac != null) {
8942                     return ac.getAccessibleChildrenCount();
8943                 } else {
8944                     return 0;
8945                 }
8946             }
8947 
8948             /**
8949              * Returns the specified <code>Accessible</code> child of the
8950              * object.
8951              *
8952              * @param i zero-based index of child
8953              * @return the <code>Accessible</code> child of the object
8954              */
8955             public Accessible getAccessibleChild(int i) {
8956                 AccessibleContext ac = getCurrentAccessibleContext();
8957                 if (ac != null) {
8958                     Accessible accessibleChild = ac.getAccessibleChild(i);
8959                     ac.setAccessibleParent(this);
8960                     return accessibleChild;
8961                 } else {
8962                     return null;
8963                 }
8964             }
8965 
8966             /**
8967              * Gets the locale of the component. If the component
8968              * does not have a locale, then the locale of its parent
8969              * is returned.
8970              *
8971              * @return this component's locale; if this component does
8972              *    not have a locale, the locale of its parent is returned
8973              * @exception IllegalComponentStateException if the
8974              *    <code>Component</code> does not have its own locale
8975              *    and has not yet been added to a containment hierarchy
8976              *    such that the locale can be determined from the
8977              *    containing parent
8978              * @see #setLocale
8979              */
8980             public Locale getLocale() {
8981                 AccessibleContext ac = getCurrentAccessibleContext();
8982                 if (ac != null) {
8983                     return ac.getLocale();
8984                 } else {
8985                     return null;
8986                 }
8987             }
8988 
8989             /**
8990              * Adds a <code>PropertyChangeListener</code> to the listener list.
8991              * The listener is registered for all properties.
8992              *
8993              * @param l  the <code>PropertyChangeListener</code>
8994              *     to be added
8995              */
8996             public void addPropertyChangeListener(PropertyChangeListener l) {
8997                 AccessibleContext ac = getCurrentAccessibleContext();
8998                 if (ac != null) {
8999                     ac.addPropertyChangeListener(l);
9000                 } else {
9001                     super.addPropertyChangeListener(l);
9002                 }
9003             }
9004 
9005             /**
9006              * Removes a <code>PropertyChangeListener</code> from the
9007              * listener list. This removes a <code>PropertyChangeListener</code>
9008              * that was registered for all properties.
9009              *
9010              * @param l  the <code>PropertyChangeListener</code>
9011              *    to be removed
9012              */
9013             public void removePropertyChangeListener(PropertyChangeListener l) {
9014                 AccessibleContext ac = getCurrentAccessibleContext();
9015                 if (ac != null) {
9016                     ac.removePropertyChangeListener(l);
9017                 } else {
9018                     super.removePropertyChangeListener(l);
9019                 }
9020             }
9021 
9022             /**
9023              * Gets the <code>AccessibleAction</code> associated with this
9024              * object if one exists.  Otherwise returns <code>null</code>.
9025              *
9026              * @return the <code>AccessibleAction</code>, or <code>null</code>
9027              */
9028             public AccessibleAction getAccessibleAction() {
9029                 return getCurrentAccessibleContext().getAccessibleAction();
9030             }
9031 
9032             /**
9033              * Gets the <code>AccessibleComponent</code> associated with
9034              * this object if one exists.  Otherwise returns <code>null</code>.
9035              *
9036              * @return the <code>AccessibleComponent</code>, or
9037              *    <code>null</code>
9038              */
9039             public AccessibleComponent getAccessibleComponent() {
9040                 return this; // to override getBounds()
9041             }
9042 
9043             /**
9044              * Gets the <code>AccessibleSelection</code> associated with
9045              * this object if one exists.  Otherwise returns <code>null</code>.
9046              *
9047              * @return the <code>AccessibleSelection</code>, or
9048              *    <code>null</code>
9049              */
9050             public AccessibleSelection getAccessibleSelection() {
9051                 return getCurrentAccessibleContext().getAccessibleSelection();
9052             }
9053 
9054             /**
9055              * Gets the <code>AccessibleText</code> associated with this
9056              * object if one exists.  Otherwise returns <code>null</code>.
9057              *
9058              * @return the <code>AccessibleText</code>, or <code>null</code>
9059              */
9060             public AccessibleText getAccessibleText() {
9061                 return getCurrentAccessibleContext().getAccessibleText();
9062             }
9063 
9064             /**
9065              * Gets the <code>AccessibleValue</code> associated with
9066              * this object if one exists.  Otherwise returns <code>null</code>.
9067              *
9068              * @return the <code>AccessibleValue</code>, or <code>null</code>
9069              */
9070             public AccessibleValue getAccessibleValue() {
9071                 return getCurrentAccessibleContext().getAccessibleValue();
9072             }
9073 
9074 
9075             // AccessibleComponent methods ==========
9076 
9077             /**
9078              * Gets the background color of this object.
9079              *
9080              * @return the background color, if supported, of the object;
9081              *     otherwise, <code>null</code>
9082              */
9083             public Color getBackground() {
9084                 AccessibleContext ac = getCurrentAccessibleContext();
9085                 if (ac instanceof AccessibleComponent) {
9086                     return ((AccessibleComponent) ac).getBackground();
9087                 } else {
9088                     Component c = getCurrentComponent();
9089                     if (c != null) {
9090                         return c.getBackground();
9091                     } else {
9092                         return null;
9093                     }
9094                 }
9095             }
9096 
9097             /**
9098              * Sets the background color of this object.
9099              *
9100              * @param c the new <code>Color</code> for the background
9101              */
9102             public void setBackground(Color c) {
9103                 AccessibleContext ac = getCurrentAccessibleContext();
9104                 if (ac instanceof AccessibleComponent) {
9105                     ((AccessibleComponent) ac).setBackground(c);
9106                 } else {
9107                     Component cp = getCurrentComponent();
9108                     if (cp != null) {
9109                         cp.setBackground(c);
9110                     }
9111                 }
9112             }
9113 
9114             /**
9115              * Gets the foreground color of this object.
9116              *
9117              * @return the foreground color, if supported, of the object;
9118              *     otherwise, <code>null</code>
9119              */
9120             public Color getForeground() {
9121                 AccessibleContext ac = getCurrentAccessibleContext();
9122                 if (ac instanceof AccessibleComponent) {
9123                     return ((AccessibleComponent) ac).getForeground();
9124                 } else {
9125                     Component c = getCurrentComponent();
9126                     if (c != null) {
9127                         return c.getForeground();
9128                     } else {
9129                         return null;
9130                     }
9131                 }
9132             }
9133 
9134             /**
9135              * Sets the foreground color of this object.
9136              *
9137              * @param c the new <code>Color</code> for the foreground
9138              */
9139             public void setForeground(Color c) {
9140                 AccessibleContext ac = getCurrentAccessibleContext();
9141                 if (ac instanceof AccessibleComponent) {
9142                     ((AccessibleComponent) ac).setForeground(c);
9143                 } else {
9144                     Component cp = getCurrentComponent();
9145                     if (cp != null) {
9146                         cp.setForeground(c);
9147                     }
9148                 }
9149             }
9150 
9151             /**
9152              * Gets the <code>Cursor</code> of this object.
9153              *
9154              * @return the <code>Cursor</code>, if supported,
9155              *    of the object; otherwise, <code>null</code>
9156              */
9157             public Cursor getCursor() {
9158                 AccessibleContext ac = getCurrentAccessibleContext();
9159                 if (ac instanceof AccessibleComponent) {
9160                     return ((AccessibleComponent) ac).getCursor();
9161                 } else {
9162                     Component c = getCurrentComponent();
9163                     if (c != null) {
9164                         return c.getCursor();
9165                     } else {
9166                         Accessible ap = getAccessibleParent();
9167                         if (ap instanceof AccessibleComponent) {
9168                             return ((AccessibleComponent) ap).getCursor();
9169                         } else {
9170                             return null;
9171                         }
9172                     }
9173                 }
9174             }
9175 
9176             /**
9177              * Sets the <code>Cursor</code> of this object.
9178              *
9179              * @param c the new <code>Cursor</code> for the object
9180              */
9181             public void setCursor(Cursor c) {
9182                 AccessibleContext ac = getCurrentAccessibleContext();
9183                 if (ac instanceof AccessibleComponent) {
9184                     ((AccessibleComponent) ac).setCursor(c);
9185                 } else {
9186                     Component cp = getCurrentComponent();
9187                     if (cp != null) {
9188                         cp.setCursor(c);
9189                     }
9190                 }
9191             }
9192 
9193             /**
9194              * Gets the <code>Font</code> of this object.
9195              *
9196              * @return the <code>Font</code>,if supported,
9197              *   for the object; otherwise, <code>null</code>
9198              */
9199             public Font getFont() {
9200                 AccessibleContext ac = getCurrentAccessibleContext();
9201                 if (ac instanceof AccessibleComponent) {
9202                     return ((AccessibleComponent) ac).getFont();
9203                 } else {
9204                     Component c = getCurrentComponent();
9205                     if (c != null) {
9206                         return c.getFont();
9207                     } else {
9208                         return null;
9209                     }
9210                 }
9211             }
9212 
9213             /**
9214              * Sets the <code>Font</code> of this object.
9215              *
9216              * @param f the new <code>Font</code> for the object
9217              */
9218             public void setFont(Font f) {
9219                 AccessibleContext ac = getCurrentAccessibleContext();
9220                 if (ac instanceof AccessibleComponent) {
9221                     ((AccessibleComponent) ac).setFont(f);
9222                 } else {
9223                     Component c = getCurrentComponent();
9224                     if (c != null) {
9225                         c.setFont(f);
9226                     }
9227                 }
9228             }
9229 
9230             /**
9231              * Gets the <code>FontMetrics</code> of this object.
9232              *
9233              * @param f the <code>Font</code>
9234              * @return the <code>FontMetrics</code> object, if supported;
9235              *    otherwise <code>null</code>
9236              * @see #getFont
9237              */
9238             public FontMetrics getFontMetrics(Font f) {
9239                 AccessibleContext ac = getCurrentAccessibleContext();
9240                 if (ac instanceof AccessibleComponent) {
9241                     return ((AccessibleComponent) ac).getFontMetrics(f);
9242                 } else {
9243                     Component c = getCurrentComponent();
9244                     if (c != null) {
9245                         return c.getFontMetrics(f);
9246                     } else {
9247                         return null;
9248                     }
9249                 }
9250             }
9251 
9252             /**
9253              * Determines if the object is enabled.
9254              *
9255              * @return true if object is enabled; otherwise, false
9256              */
9257             public boolean isEnabled() {
9258                 AccessibleContext ac = getCurrentAccessibleContext();
9259                 if (ac instanceof AccessibleComponent) {
9260                     return ((AccessibleComponent) ac).isEnabled();
9261                 } else {
9262                     Component c = getCurrentComponent();
9263                     if (c != null) {
9264                         return c.isEnabled();
9265                     } else {
9266                         return false;
9267                     }
9268                 }
9269             }
9270 
9271             /**
9272              * Sets the enabled state of the object.
9273              *
9274              * @param b if true, enables this object; otherwise, disables it
9275              */
9276             public void setEnabled(boolean b) {
9277                 AccessibleContext ac = getCurrentAccessibleContext();
9278                 if (ac instanceof AccessibleComponent) {
9279                     ((AccessibleComponent) ac).setEnabled(b);
9280                 } else {
9281                     Component c = getCurrentComponent();
9282                     if (c != null) {
9283                         c.setEnabled(b);
9284                     }
9285                 }
9286             }
9287 
9288             /**
9289              * Determines if this object is visible.  Note: this means that the
9290              * object intends to be visible; however, it may not in fact be
9291              * showing on the screen because one of the objects that this object
9292              * is contained by is not visible.  To determine if an object is
9293              * showing on the screen, use <code>isShowing</code>.
9294              *
9295              * @return true if object is visible; otherwise, false
9296              */
9297             public boolean isVisible() {
9298                 AccessibleContext ac = getCurrentAccessibleContext();
9299                 if (ac instanceof AccessibleComponent) {
9300                     return ((AccessibleComponent) ac).isVisible();
9301                 } else {
9302                     Component c = getCurrentComponent();
9303                     if (c != null) {
9304                         return c.isVisible();
9305                     } else {
9306                         return false;
9307                     }
9308                 }
9309             }
9310 
9311             /**
9312              * Sets the visible state of the object.
9313              *
9314              * @param b if true, shows this object; otherwise, hides it
9315              */
9316             public void setVisible(boolean b) {
9317                 AccessibleContext ac = getCurrentAccessibleContext();
9318                 if (ac instanceof AccessibleComponent) {
9319                     ((AccessibleComponent) ac).setVisible(b);
9320                 } else {
9321                     Component c = getCurrentComponent();
9322                     if (c != null) {
9323                         c.setVisible(b);
9324                     }
9325                 }
9326             }
9327 
9328             /**
9329              * Determines if the object is showing.  This is determined
9330              * by checking the visibility of the object and ancestors
9331              * of the object.  Note: this will return true even if the
9332              * object is obscured by another (for example,
9333              * it happens to be underneath a menu that was pulled down).
9334              *
9335              * @return true if the object is showing; otherwise, false
9336              */
9337             public boolean isShowing() {
9338                 AccessibleContext ac = getCurrentAccessibleContext();
9339                 if (ac instanceof AccessibleComponent) {
9340                     if (ac.getAccessibleParent() != null) {
9341                         return ((AccessibleComponent) ac).isShowing();
9342                     } else {
9343                         // Fixes 4529616 - AccessibleJTableCell.isShowing()
9344                         // returns false when the cell on the screen
9345                         // if no parent
9346                         return isVisible();
9347                     }
9348                 } else {
9349                     Component c = getCurrentComponent();
9350                     if (c != null) {
9351                         return c.isShowing();
9352                     } else {
9353                         return false;
9354                     }
9355                 }
9356             }
9357 
9358             /**
9359              * Checks whether the specified point is within this
9360              * object's bounds, where the point's x and y coordinates
9361              * are defined to be relative to the coordinate system of
9362              * the object.
9363              *
9364              * @param p the <code>Point</code> relative to the
9365              *    coordinate system of the object
9366              * @return true if object contains <code>Point</code>;
9367              *    otherwise false
9368              */
9369             public boolean contains(Point p) {
9370                 AccessibleContext ac = getCurrentAccessibleContext();
9371                 if (ac instanceof AccessibleComponent) {
9372                     Rectangle r = ((AccessibleComponent) ac).getBounds();
9373                     return r.contains(p);
9374                 } else {
9375                     Component c = getCurrentComponent();
9376                     if (c != null) {
9377                         Rectangle r = c.getBounds();
9378                         return r.contains(p);
9379                     } else {
9380                         return getBounds().contains(p);
9381                     }
9382                 }
9383             }
9384 
9385             /**
9386              * Returns the location of the object on the screen.
9387              *
9388              * @return location of object on screen -- can be
9389              *    <code>null</code> if this object is not on the screen
9390              */
9391             public Point getLocationOnScreen() {
9392                 if (parent != null) {
9393                     Point parentLocation = parent.getLocationOnScreen();
9394                     Point componentLocation = getLocation();
9395                     componentLocation.translate(parentLocation.x, parentLocation.y);
9396                     return componentLocation;
9397                 } else {
9398                     return null;
9399                 }
9400             }
9401 
9402             /**
9403              * Gets the location of the object relative to the parent
9404              * in the form of a point specifying the object's
9405              * top-left corner in the screen's coordinate space.
9406              *
9407              * @return an instance of <code>Point</code> representing
9408              *    the top-left corner of the object's bounds in the
9409              *    coordinate space of the screen; <code>null</code> if
9410              *    this object or its parent are not on the screen
9411              */
9412             public Point getLocation() {
9413                 if (parent != null) {
9414                     Rectangle r = parent.getHeaderRect(column);
9415                     if (r != null) {
9416                         return r.getLocation();
9417                     }
9418                 }
9419                 return null;
9420             }
9421 
9422             /**
9423              * Sets the location of the object relative to the parent.
9424              * @param p the new position for the top-left corner
9425              * @see #getLocation
9426              */
9427             public void setLocation(Point p) {
9428             }
9429 
9430             /**
9431              * Gets the bounds of this object in the form of a Rectangle object.
9432              * The bounds specify this object's width, height, and location
9433              * relative to its parent.
9434              *
9435              * @return A rectangle indicating this component's bounds; null if
9436              * this object is not on the screen.
9437              * @see #contains
9438              */
9439             public Rectangle getBounds() {
9440                 if (parent != null) {
9441                     return parent.getHeaderRect(column);
9442                 } else {
9443                     return null;
9444                 }
9445             }
9446 
9447             /**
9448              * Sets the bounds of this object in the form of a Rectangle object.
9449              * The bounds specify this object's width, height, and location
9450              * relative to its parent.
9451              *
9452              * @param r rectangle indicating this component's bounds
9453              * @see #getBounds
9454              */
9455             public void setBounds(Rectangle r) {
9456                 AccessibleContext ac = getCurrentAccessibleContext();
9457                 if (ac instanceof AccessibleComponent) {
9458                     ((AccessibleComponent) ac).setBounds(r);
9459                 } else {
9460                     Component c = getCurrentComponent();
9461                     if (c != null) {
9462                         c.setBounds(r);
9463                     }
9464                 }
9465             }
9466 
9467             /**
9468              * Returns the size of this object in the form of a Dimension object.
9469              * The height field of the Dimension object contains this object's
9470              * height, and the width field of the Dimension object contains this
9471              * object's width.
9472              *
9473              * @return A Dimension object that indicates the size of this component;
9474              * null if this object is not on the screen
9475              * @see #setSize
9476              */
9477             public Dimension getSize() {
9478                 if (parent != null) {
9479                     Rectangle r = parent.getHeaderRect(column);
9480                     if (r != null) {
9481                         return r.getSize();
9482                     }
9483                 }
9484                 return null;
9485             }
9486 
9487             /**
9488              * Resizes this object so that it has width and height.
9489              *
9490              * @param d The dimension specifying the new size of the object.
9491              * @see #getSize
9492              */
9493             public void setSize (Dimension d) {
9494                 AccessibleContext ac = getCurrentAccessibleContext();
9495                 if (ac instanceof AccessibleComponent) {
9496                     ((AccessibleComponent) ac).setSize(d);
9497                 } else {
9498                     Component c = getCurrentComponent();
9499                     if (c != null) {
9500                         c.setSize(d);
9501                     }
9502                 }
9503             }
9504 
9505             /**
9506              * Returns the Accessible child, if one exists, contained at the local
9507              * coordinate Point.
9508              *
9509              * @param p The point relative to the coordinate system of this object.
9510              * @return the Accessible, if it exists, at the specified location;
9511              * otherwise null
9512              */
9513             public Accessible getAccessibleAt(Point p) {
9514                 AccessibleContext ac = getCurrentAccessibleContext();
9515                 if (ac instanceof AccessibleComponent) {
9516                     return ((AccessibleComponent) ac).getAccessibleAt(p);
9517                 } else {
9518                     return null;
9519                 }
9520             }
9521 
9522             /**
9523              * Returns whether this object can accept focus or not.   Objects that
9524              * can accept focus will also have the AccessibleState.FOCUSABLE state
9525              * set in their AccessibleStateSets.
9526              *
9527              * @return true if object can accept focus; otherwise false
9528              * @see AccessibleContext#getAccessibleStateSet
9529              * @see AccessibleState#FOCUSABLE
9530              * @see AccessibleState#FOCUSED
9531              * @see AccessibleStateSet
9532              */
9533             public boolean isFocusTraversable() {
9534                 AccessibleContext ac = getCurrentAccessibleContext();
9535                 if (ac instanceof AccessibleComponent) {
9536                     return ((AccessibleComponent) ac).isFocusTraversable();
9537                 } else {
9538                     Component c = getCurrentComponent();
9539                     if (c != null) {
9540                         return c.isFocusTraversable();
9541                     } else {
9542                         return false;
9543                     }
9544                 }
9545             }
9546 
9547             /**
9548              * Requests focus for this object.  If this object cannot accept focus,
9549              * nothing will happen.  Otherwise, the object will attempt to take
9550              * focus.
9551              * @see #isFocusTraversable
9552              */
9553             public void requestFocus() {
9554                 AccessibleContext ac = getCurrentAccessibleContext();
9555                 if (ac instanceof AccessibleComponent) {
9556                     ((AccessibleComponent) ac).requestFocus();
9557                 } else {
9558                     Component c = getCurrentComponent();
9559                     if (c != null) {
9560                         c.requestFocus();
9561                     }
9562                 }
9563             }
9564 
9565             /**
9566              * Adds the specified focus listener to receive focus events from this
9567              * component.
9568              *
9569              * @param l the focus listener
9570              * @see #removeFocusListener
9571              */
9572             public void addFocusListener(FocusListener l) {
9573                 AccessibleContext ac = getCurrentAccessibleContext();
9574                 if (ac instanceof AccessibleComponent) {
9575                     ((AccessibleComponent) ac).addFocusListener(l);
9576                 } else {
9577                     Component c = getCurrentComponent();
9578                     if (c != null) {
9579                         c.addFocusListener(l);
9580                     }
9581                 }
9582             }
9583 
9584             /**
9585              * Removes the specified focus listener so it no longer receives focus
9586              * events from this component.
9587              *
9588              * @param l the focus listener
9589              * @see #addFocusListener
9590              */
9591             public void removeFocusListener(FocusListener l) {
9592                 AccessibleContext ac = getCurrentAccessibleContext();
9593                 if (ac instanceof AccessibleComponent) {
9594                     ((AccessibleComponent) ac).removeFocusListener(l);
9595                 } else {
9596                     Component c = getCurrentComponent();
9597                     if (c != null) {
9598                         c.removeFocusListener(l);
9599                     }
9600                 }
9601             }
9602 
9603         } // inner class AccessibleJTableHeaderCell
9604 
9605     }  // inner class AccessibleJTable
9606 
9607 }  // End of Class JTable